• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

MarkUsProject / Markus / 27251757272

10 Jun 2026 03:46AM UTC coverage: 90.293% (-0.01%) from 90.303%
27251757272

Pull #7997

github

web-flow
Merge dadf20efc into 753af008a
Pull Request #7997: Add pagination to Admin Users table for performance

1067 of 2259 branches covered (47.23%)

Branch coverage included in aggregate %.

62 of 69 new or added lines in 3 files covered. (89.86%)

1 existing line in 1 file now uncovered.

46334 of 50238 relevant lines covered (92.23%)

126.49 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

74.42
/app/javascript/Components/admin_users_list.jsx
1
import React from "react";
2
import {createRoot} from "react-dom/client";
3
import ReactTable from "react-table";
4
import {selectFilter} from "./Helpers/table_helpers";
5
import {faPencil} from "@fortawesome/free-solid-svg-icons";
6
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
7

8
export class AdminUsersList extends React.Component {
9
  constructor() {
10
    super();
2✔
11
    this.state = {
2✔
12
      users: [],
13
      pages: 0,
14
      loading: true,
15
      page: 0,
16
      pageSize: 100,
17
    };
18
    this.previousFiltered = "[]";
2✔
19
    this.previousSorted = "[]";
2✔
20
  }
21

22
  fetchDataServerSide = state => {
2✔
23
    this.setState({loading: true});
3✔
24
    const currentFilteredStr = JSON.stringify(state.filtered);
3✔
25
    const currentSortedStr = JSON.stringify(state.sorted);
3✔
26

27
    let targetPage = state.page;
3✔
28
    if (this.previousFiltered !== currentFilteredStr || this.previousSorted !== currentSortedStr) {
3!
29
      targetPage = 0;
3✔
30
      this.previousFiltered = currentFilteredStr;
3✔
31
      this.previousSorted = currentSortedStr;
3✔
32
    }
33

34
    const params = new URLSearchParams({
3✔
35
      page: targetPage + 1,
36
      per_page: state.pageSize,
37
      sorted: currentSortedStr,
38
      filtered: currentFilteredStr,
39
    });
40

41
    fetch(`${Routes.admin_users_path()}?${params.toString()}`, {
3✔
42
      headers: {Accept: "application/json"},
43
    })
44
      .then(response => {
45
        if (response.ok) return response.json();
3!
NEW
46
        throw new Error("Failed to fetch grid data");
×
47
      })
48
      .then(data => {
49
        this.setState({
3✔
50
          users: data && data.users ? data.users : [],
9!
51
          pages: data && data.total_pages ? data.total_pages : 1,
9!
52
          loading: false,
53
          page: targetPage,
54
          pageSize: state.pageSize,
55
        });
56
      })
57
      .catch(err => {
NEW
58
        console.error("Pagination error:", err);
×
NEW
59
        this.setState({users: [], pages: 1, loading: false});
×
60
      });
61
  };
62

63
  columns = [
2✔
64
    {
65
      Header: I18n.t("activerecord.attributes.user.user_name"),
66
      accessor: "user_name",
67
      id: "user_name",
68
      minWidth: 120,
69
    },
70
    {
71
      Header: I18n.t("activerecord.attributes.user.first_name"),
72
      accessor: "first_name",
73
      minWidth: 120,
74
    },
75
    {
76
      Header: I18n.t("activerecord.attributes.user.last_name"),
77
      accessor: "last_name",
78
      minWidth: 120,
79
    },
80
    {
81
      Header: I18n.t("activerecord.attributes.user.email"),
82
      accessor: "email",
83
      minWidth: 150,
84
    },
85
    {
86
      Header: I18n.t("activerecord.attributes.user.id_number"),
87
      accessor: "id_number",
88
      minWidth: 90,
89
      className: "number",
90
    },
91
    {
92
      Header: I18n.t("activerecord.attributes.user.user_type"),
93
      accessor: "type",
94
      minWidth: 90,
95
      Cell: ({value}) =>
96
        value === "AdminUser"
1!
97
          ? I18n.t("activerecord.models.admin_user.one")
98
          : I18n.t("activerecord.models.end_user.one"),
99
      Filter: selectFilter,
100
      filterOptions: [
101
        {text: I18n.t("activerecord.models.admin_user.one"), value: "AdminUser"},
102
        {text: I18n.t("activerecord.models.end_user.one"), value: "EndUser"},
103
      ],
104
    },
105
    {
106
      Header: I18n.t("actions"),
107
      accessor: "id",
108
      minWidth: 70,
109
      Cell: ({value}) => (
110
        <a
1✔
111
          href={Routes.edit_admin_user_path(value)}
112
          aria-label={I18n.t("edit")}
113
          title={I18n.t("edit")}
114
        >
115
          <FontAwesomeIcon icon={faPencil} />
116
        </a>
117
      ),
118
      sortable: false,
119
      filterable: false,
120
    },
121
  ];
122

123
  render() {
124
    return (
6✔
125
      <ReactTable
126
        manual
127
        data={this.state.users}
128
        pages={this.state.pages}
129
        page={this.state.page}
130
        pageSize={this.state.pageSize}
131
        columns={this.columns}
132
        filterable
133
        showPagination={true}
134
        showPaginationBottom={true}
135
        showPageSizeOptions={false}
136
        defaultPageSize={100}
137
        defaultSorted={[{id: "user_name"}]}
138
        loading={this.state.loading}
139
        onFetchData={this.fetchDataServerSide}
NEW
140
        onPageChange={page => this.setState({page})}
×
141
      />
142
    );
143
  }
144
}
145

146
export function makeAdminUsersList(elem, props) {
147
  const root = createRoot(elem);
×
148
  root.render(<AdminUsersList {...props} />);
×
149
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc