Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[data grid] Missing MuiDataGrid-cell--withRightBorder class on last cell in row #15950

Closed
dhsj8405 opened this issue Dec 20, 2024 · 6 comments
Closed
Labels
component: data grid This is the name of the generic UI component, not the React module! customization: css Design CSS customizability

Comments

@dhsj8405
Copy link

dhsj8405 commented Dec 20, 2024

Steps to reproduce

Code example
import { Stack } from "@mui/material";
import { GridAlignment, GridColumnGroupingModel } from "@mui/x-data-grid";
import { DataGridPremium, GridColDef } from "@mui/x-data-grid-premium";
import { useEffect, useState } from "react";

type ReportMap = {
  id: number;
  tranKindName: string;
  grade1Name: string;
  grade2Name: string;
  grade3Name: string;
  grade4Name: string;
  grade5Name: string;
  grade6Name: string;
  TotalCount: number;
  TotalAmount: number;
};

type TotalRowType = ReportMap & {
  id: string | number;
};

const initialColumns: GridColDef[] = [
  {
    field: "tranKindName",
    headerName: "종류",
    minWidth: 100,
    flex: 2,
    sortable: false,
  },
  {
    field: "grade3Name",
    headerName: "deptA",
    minWidth: 100,
    flex: 2,
    sortable: false,
    rowSpanValueGetter: (value, row) =>
      getRowSpanValue(value, row, "grade3Name"),
  },
  {
    field: "grade4Name",
    headerName: "deptB",
    minWidth: 100,
    flex: 2,
    sortable: false,
    rowSpanValueGetter: (value, row) =>
      getRowSpanValue(value, row, "grade4Name"),
  },
  {
    field: "grade5Name",
    headerName: "deptC",
    minWidth: 100,
    flex: 2,
    sortable: false,
    rowSpanValueGetter: (value, row) =>
      getRowSpanValue(value, row, "grade5Name"),
  },
  {
    field: "grade6Name",
    headerName: "deptD",
    minWidth: 100,
    flex: 2,
    sortable: false,
    rowSpanValueGetter: (value, row) =>
      getRowSpanValue(value, row, "grade6Name"),
  },

  {
    field: "TotalCount",
    headerName: "총 건수",
    minWidth: 70,
    flex: 1,
    align: "right",
    sortable: false,
    type: "number",
    rowSpanValueGetter: (value, row) =>
      getRowSpanValue(value, row, "TotalCount"),
  },
  {
    field: "TotalAmount",
    headerName: "총 금액",
    minWidth: 110,
    flex: 2,
    align: "right",
    sortable: false,
    type: "number",
    rowSpanValueGetter: (value, row) =>
      getRowSpanValue(value, row, "TotalAmount"),
  },
];

const totalSumColumnGroupModel: GridColumnGroupingModel = [
  {
    groupId: "sumTot",
    headerName: "총 합계",
    description: "",
    children: [{ field: "TotalCount" }, { field: "TotalAmount" }],
  },
];

const getRowSpanValue = (value, row, currentField) => {
  if (!row) return value;

  const fields = Object.keys(row)
    .filter((key) => key !== "id")
    .slice(0, Object.keys(row).indexOf(currentField));

  return fields.map((field) => row[field]).join("-");
};

const now = new Date();
const startDate = new Date();
startDate.setDate(now.getDate() - 7); // 현재 날짜에서 7일을 뺌

const Page = () => {
  const [originRows, setOriginRows] = useState<ReportMap[]>([]);
  const [rows, setRows] = useState<ReportMap[]>([]);
  const [columns, setColumns] = useState<GridColDef[]>([]);
  const [gradeLevel, setGradeLevel] = useState(6);
  const [loading, setLoading] = useState(false);
  const [slotDays, setSlotDays] = useState<string[]>([]);
  const [totalRow, setTotalRow] = useState<TotalRowType>({
    id: "totalRowId",
    tranKindName: "",
    grade1Name: "",
    grade2Name: "",
    grade3Name: "",
    grade4Name: "",
    grade5Name: "",
    grade6Name: "",
    TotalCount: 0,
    TotalAmount: 0,
  });
  const [columnGroupingModel, setColumnGroupingModel] =
    useState<GridColumnGroupingModel>([]);

  useEffect(() => {
    setRows(originRows);
  }, [originRows]);

  const generateGrades = (departmentId, departments) => {
    const departmentMap = departments.reduce((map, dept) => {
      map[dept.id] = dept;
      return map;
    }, {});

    const grades = [];
    let currentDept = departmentMap[departmentId];

    // 상위 부서부터 추적하여 grades 배열에 추가
    while (currentDept) {
      grades.unshift(currentDept.departmentName);
      currentDept = currentDept.parentId
        ? departmentMap[currentDept.parentId]
        : null;
    }

    return {
      grade3Name: grades[0] || "",
      grade4Name: grades[1] || "",
      grade5Name: grades[2] || "",
      grade6Name: grades[3] || "",
    };
  };

  useEffect(() => {
    // 동적 컬럼생성
    if (rows.length > 0) {
      setSlotDays(makeDateColumns(rows[0]));
    } else {
      setSlotDays([]);
    }
  }, [rows]);

  useEffect(() => {
    const dynamicColumns: GridColDef[] = slotDays
      .map((key) => [
        {
          field: `Count_${key}`,
          headerName: "건수",
          flex: 1,
          minWidth: 70,
          align: "right" as GridAlignment,
          sortable: false,
          type: "number",
          rowSpanValueGetter: (value, row) =>
            getRowSpanValue(value, row, `Count_${key}`),
        } as GridColDef,
        {
          field: `Amount_${key}`,
          headerName: "금액",
          flex: 2,
          minWidth: 110,
          align: "right" as GridAlignment,
          sortable: false,
          type: "number",
          rowSpanValueGetter: (value, row) =>
            getRowSpanValue(value, row, `Amount_${key}`),
        } as GridColDef,
      ])
      .flat();
    const dateColumnGroupingModel: GridColumnGroupingModel = [
      ...slotDays.map((key) => ({
        groupId: key,
        headerName: key,
        description: "",
        children: [{ field: `Count_${key}` }, { field: `Amount_${key}` }],
      })),
    ];

    const filteredColumns = [...initialColumns, ...dynamicColumns].filter(
      (column) => {
        if (gradeLevel >= 6) {
          return true;
        } else if (gradeLevel >= 5) {
          return column.field !== "grade6Name";
        } else if (gradeLevel >= 4) {
          return column.field !== "grade6Name" && column.field !== "grade5Name";
        } else if (gradeLevel >= 3) {
          return (
            column.field !== "grade6Name" &&
            column.field !== "grade5Name" &&
            column.field !== "grade4Name"
          );
        } else {
          return (
            column.field !== "grade6Name" &&
            column.field !== "grade5Name" &&
            column.field !== "grade4Name" &&
            column.field !== "grade3Name"
          );
        }
      },
    );
    const filteredFields: string[] = filteredColumns.map((col) => col.field);

    const filteredDateColumnGroupModel = dateColumnGroupingModel
      .map((group) => ({
        ...group,
        children: group.children.filter(
          (child) => "field" in child && filteredFields.includes(child.field),
        ),
      }))
      .filter((group) => group.children.length > 0);

    setColumns(filteredColumns);

    setTotalRow({
      ...calculateSummaryRow(rows, filteredColumns),
    });
    setColumnGroupingModel([
      ...totalSumColumnGroupModel,
      ...filteredDateColumnGroupModel,
    ]);
  }, [slotDays]);

  const calculateSummaryRow = (
    rows: any[],
    filteredColumns: any[],
  ): TotalRowType => {
    const summaryRow: TotalRowType = {
      id: "totalRowId",
      tranKindName: "",
      grade1Name: "",
      grade2Name: "",
      grade3Name: "",
      grade4Name: "",
      grade5Name: "",
      grade6Name: "",
      TotalCount: 0,
      TotalAmount: 0,
    };

    filteredColumns.forEach((column, idx) => {
      if (column.type === "number") {
        summaryRow[column.field] = rows.reduce(
          (acc, row) => acc + (row[column.field] || 0),
          0,
        );
      } else {
        if (idx === 0) {
          summaryRow[column.field] = "합계";
        }
      }
    });

    return summaryRow;
  };

  useEffect(() => {
    getList();
  }, []);

  const getList = async () => {
    setLoading(true);

    const responseData = {
      reportMaps: [
        {
          id: 1,
          tranKindName: "test1",
          grade1Name: "",
          grade2Name: "",
          grade3Name: "",
          grade4Name: "",
          grade5Name: "",
          grade6Name: "",
          TotalCount: 30,
          TotalAmount: 1020000.0,
          "Count_2024-11-21": 3,
          "Amount_2024-11-21": 140000.0,
          "ReceiptIds_2024-11-21": "",
          "Count_2024-11-20": 1,
          "Amount_2024-11-20": 40000.0,
          "ReceiptIds_2024-11-20": "",
          "Count_2024-11-30": 2,
          "Amount_2024-11-30": 80000.0,
          "ReceiptIds_2024-11-30": "",
          "Count_2024-11-19": 1,
          "Amount_2024-11-19": 40000.0,
          "ReceiptIds_2024-11-19": "",
          "Count_2024-11-18": 2,
          "Amount_2024-11-18": 40000.0,
          "ReceiptIds_2024-11-18": "",
          "Count_2024-11-16": 1,
          "Amount_2024-11-16": 0.0,
          "ReceiptIds_2024-11-16": "",
          "Count_2024-11-15": 3,
          "Amount_2024-11-15": 100000.0,
          "ReceiptIds_2024-11-15": "",
          "Count_2024-11-14": 4,
          "Amount_2024-11-14": 140000.0,
          "ReceiptIds_2024-11-14": "",
          "Count_2024-12-04": 1,
          "Amount_2024-12-04": 60000.0,
          "ReceiptIds_2024-12-04": "",
          "Count_2024-11-13": 5,
          "Amount_2024-11-13": 140000.0,
          "ReceiptIds_2024-11-13": "",
          "Count_2024-12-03": 1,
          "Amount_2024-12-03": 60000.0,
          "ReceiptIds_2024-12-03": "",
          "Count_2024-11-12": 3,
          "Amount_2024-11-12": 60000.0,
          "ReceiptIds_2024-11-12": "",
          "Count_2024-12-02": 1,
          "Amount_2024-12-02": 60000.0,
          "ReceiptIds_2024-12-02": "",
          "Count_2024-11-22": 1,
          "Amount_2024-11-22": 0.0,
          "ReceiptIds_2024-11-22": "",
          "Count_2024-12-01": 1,
          "Amount_2024-12-01": 60000.0,
          "ReceiptIds_2024-12-01": "",
        },
      ],
      departmentMaps: [
        {
          departmentName: "부서1",
          id: 1,
          parentId: null,
          order: 1,
        },
        {
          departmentName: "부서2",
          id: 2,
          parentId: 1,
          order: 2,
        },
        {
          departmentName: "부서3",
          id: 3,
          parentId: 2,
          order: 3,
        },
      ],
    };

    setLoading(false);

    const reportDatas = responseData.reportMaps;
    setOriginRows(reportDatas);
  };

  const makeDateColumns = (data: Record<string, any>): string[] => {
    return Object.keys(data)
      .filter((key) => key.startsWith("Amount_")) // "Amount_"로 시작하는 키만 필터링
      .map((key) => key.replace("Amount_", "")) // "Amount_"를 제거한 키 생성
      .sort(); // 문자열 순서대로 정렬
  };

  return (
    <>
      <Stack spacing={0}>
        <DataGridPremium
          columns={columns}
          rows={rows}
          loading={loading}
          disableColumnReorder
          disableColumnMenu
          unstable_rowSpanning
          columnGroupingModel={columnGroupingModel}
          hideFooter
          showColumnVerticalBorder
          showCellVerticalBorder
          pinnedColumns={{
            left: [
              "tranKindName",
              "grade1Name",
              "grade2Name",
              "grade3Name",
              "grade4Name",
              "grade5Name",
              "grade6Name",
            ],
          }}
          pinnedRows={{
            bottom: [{ ...totalRow }],
          }}
        />
      </Stack>
    </>
  );
};

export default Page;

Current behavior

In the MUI DataGrid, the cells in the last column do not have the MuiDataGrid-cell--withRightBorder class applied. This results in the absence of a right-side border for those cells, despite showCellVerticalBorder being enabled.

Expected behavior

This issue is causing inconsistent styling in the DataGrid, particularly when vertical borders are expected to be displayed on all cells for a clean and structured layout. It negatively impacts the visual appearance of the grid, especially in applications that rely on strict UI alignment.

The issue persists regardless of whether columns are dynamically or statically defined. A prompt resolution or workaround would be greatly appreciated to maintain consistent UI behavior.

Context

This issue is causing inconsistent styling in the DataGrid, particularly when vertical borders are expected to be displayed on all cells for a clean and structured layout. It negatively impacts the visual appearance of the grid, especially in applications that rely on strict UI alignment.

The issue persists regardless of whether columns are dynamically or statically defined. A prompt resolution or workaround would be greatly appreciated to maintain consistent UI behavior.

image

Your environment

`npx @mui/envinfo`
npx @mui/envinfo
Need to install the following packages:
@mui/[email protected]
Ok to proceed? (y) y

System:
OS: Windows 11 10.0.22631
Binaries:
 Node: 18.17.0 - C:\Program Files\nodejs\node.EXE
    npm: 9.6.7 - C:\Program Files\nodejs\npm.CMD
    pnpm: 9.4.0 - ~\AppData\Roaming\npm\pnpm.CMD
Browsers:
Chrome: Not Found
Edge: Chromium (131.0.2903.70)
npmPackages:
@emotion/react: ^11.11.1 => 11.11.3
@emotion/styled: ^11.11.0 => 11.11.0
@mui/icons-material: ^5.14.8 => 5.15.7
@mui/lab: 5.0.0-alpha.120 => 5.0.0-alpha.120
@mui/material: ^5.15.14 => 5.15.14
@mui/styled-engine-sc: ^5.14.8 => 5.14.12
@mui/system: ^5.15.14 => 5.15.14
@mui/x-data-grid: ^7.22.3 => 7.22.3
@mui/x-data-grid-generator: ^6.13.0 => 6.19.3
@mui/x-data-grid-premium: ^7.22.3 => 7.22.3
@mui/x-data-grid-pro: ^7.22.3 => 7.22.3
@mui/x-date-pickers: ^6.14.0 => 6.19.3
@mui/x-date-pickers-pro: ^6.13.0 => 6.19.3
@mui/x-license: ^7.0.0 => 7.21.0
@mui/x-tree-view: ^7.14.0 => 7.20.0
@mui/x-tree-view-pro: ^7.14.0 => 7.20.0
@types/react: 18.0.28 => 18.0.28
react: 18.2.0 => 18.2.0
react-dom: 18.2.0 => 18.2.0
styled-components: ^5.3.11 => 5.3.11

Search keywords: withRightBorder, Last Column's Cells

@dhsj8405 dhsj8405 added bug 🐛 Something doesn't work status: waiting for maintainer These issues haven't been looked at yet by a maintainer labels Dec 20, 2024
@michelengelen
Copy link
Member

Hey @dhsj8405 ... the absence of the MuiDataGrid-cell--withRightBorder class is to prevent duplicate borders on the last cell in a row, since the data grid is wrapped in a border typically as well.

Additionally adding a border would mess with the virtualization logic and could lead to unwanted scrolling behavior.

@KenanYusuf do you know of a workaround we could provide here that's not messing with it?

@michelengelen michelengelen changed the title Missing MuiDataGrid-cell--withRightBorder Class on Last Column's Cells [data grid] Missing MuiDataGrid-cell--withRightBorder class on last cell in row Dec 20, 2024
@michelengelen michelengelen added component: data grid This is the name of the generic UI component, not the React module! customization: css Design CSS customizability status: waiting for author Issue with insufficient information and removed status: waiting for maintainer These issues haven't been looked at yet by a maintainer labels Dec 20, 2024
@KenanYusuf
Copy link
Member

@dhsj8405 would applying a border-right on the data grid fix your issue?

<DataGridPremium sx={{ borderRight: "1px solid e0e0e0" }} />

It's hard to advise on an exact solution without having a working reproduction. I put your code into CodeSandbox and it looks different to the image on the issue.

If the above solution does not work, please could you fork this example and update it to match what you have in the screenshot? https://codesandbox.io/p/sandbox/lucid-frog-yzfxsk

@dhsj8405
Copy link
Author

dhsj8405 commented Dec 23, 2024 via email

@github-actions github-actions bot added status: waiting for maintainer These issues haven't been looked at yet by a maintainer and removed status: waiting for author Issue with insufficient information labels Dec 23, 2024
@michelengelen
Copy link
Member

So, is this resolved for you @dhsj8405 ?

@michelengelen michelengelen added status: waiting for author Issue with insufficient information and removed status: waiting for maintainer These issues haven't been looked at yet by a maintainer labels Dec 23, 2024
@dhsj8405
Copy link
Author

dhsj8405 commented Dec 23, 2024 via email

@github-actions github-actions bot added status: waiting for maintainer These issues haven't been looked at yet by a maintainer and removed status: waiting for author Issue with insufficient information labels Dec 23, 2024
Copy link

This issue has been closed. If you have a similar problem but not exactly the same, please open a new issue.
Now, if you have additional information related to this issue or things that could help future readers, feel free to leave a comment.

Note

@dhsj8405 How did we do? Your experience with our support team matters to us. If you have a moment, please share your thoughts in this short Support Satisfaction survey.

@github-actions github-actions bot removed the status: waiting for maintainer These issues haven't been looked at yet by a maintainer label Dec 24, 2024
@MBilalShafi MBilalShafi removed the bug 🐛 Something doesn't work label Dec 24, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
component: data grid This is the name of the generic UI component, not the React module! customization: css Design CSS customizability
Projects
None yet
Development

No branches or pull requests

4 participants