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

MarkUsProject / Markus / 28377234905

29 Jun 2026 01:54PM UTC coverage: 90.242% (-0.003%) from 90.245%
28377234905

Pull #8021

github

web-flow
Merge 78358be1d into 1abc7e1c4
Pull Request #8021: Migrate annotation_usage_panel.jsx to react table v8

1166 of 2420 branches covered (48.18%)

Branch coverage included in aggregate %.

14 of 14 new or added lines in 2 files covered. (100.0%)

1 existing line in 1 file now uncovered.

46917 of 50862 relevant lines covered (92.24%)

127.34 hits per line

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

79.17
/app/javascript/Components/annotation_usage_panel.jsx
1
import React from "react";
2
import {createRoot} from "react-dom/client";
3
import {createColumnHelper} from "@tanstack/react-table";
4
import Table from "./table/table";
5

6
import {caseSensitiveIncludes} from "./Helpers/table_helpers";
7

8
const columnHelper = createColumnHelper();
1✔
9
class AnnotationUsagePanel extends React.Component {
10
  constructor(props) {
11
    super(props);
3✔
12
    this.state = {
2✔
13
      applications: null,
14
      columnFilters: [],
15
      details: false,
16
    };
17
  }
18

19
  toggle = () => {
2✔
20
    if (this.state.applications === null) {
2!
21
      this.fetchData();
2✔
22
    } else {
23
      this.setState({details: !this.state.details});
×
24
    }
25
  };
26

27
  columns = [
2✔
28
    columnHelper.accessor(
29
      row => "(" + row.user_name + ") " + row.first_name + " " + row.last_name,
6✔
30
      {
31
        header: I18n.t("annotations.used_by"),
32
        id: "user",
33
        minSize: 200,
34
      }
35
    ),
36
    columnHelper.accessor("group_name", {
37
      header: I18n.t("activerecord.models.submission.one"),
38
      enableSorting: false,
39
      aggregationFn: (columnId, leafRows, childRows) => {
40
        return leafRows.reduce((acc, row) => acc + row.original.count, 0);
12✔
41
      },
42
      cell: props => {
43
        if (props.row.getIsGrouped()) {
12!
44
          return I18n.t("annotations.used_times", {
12✔
45
            count: props.row.getValue("group_name"),
46
          });
47
        }
48

UNCOV
49
        return (
×
50
          <a
51
            href={Routes.edit_course_result_path(
52
              this.props.course_id,
53
              props.row.original.result_id
54
            )}
55
          >
56
            {props.row.original.group_name +
57
              (props.row.original.count > 1 ? ` (${props.row.original.count})` : "")}
×
58
          </a>
59
        );
60
      },
61
      filterFn: (row, columnId, filterValue) => {
62
        const value = filterValue?.value;
9✔
63
        const caseSensitive = filterValue?.caseSensitive;
9✔
64

65
        if (!value) return true;
9✔
66

67
        return caseSensitiveIncludes(row.original[columnId], value, caseSensitive);
6✔
68
      },
69
      meta: {
70
        filterVariant: "case-sensitive-text",
71
      },
72
    }),
73
  ];
74

75
  fetchData = () => {
2✔
76
    const url = Routes.annotation_text_uses_course_assignment_annotation_categories_path(
2✔
77
      this.props.course_id,
78
      this.props.assignment_id,
79
      {
80
        annotation_text_id: this.props.annotation_id,
81
      }
82
    );
83
    fetch(url, {
2✔
84
      headers: {
85
        Accept: "application/json",
86
      },
87
    })
88
      .then(response => {
89
        if (response.ok) {
2!
90
          return response.json();
2✔
91
        }
92
      })
93
      .then(res => {
94
        this.setState({applications: res, details: true});
2✔
95
      });
96
  };
97

98
  render() {
99
    let numUsed = <p>{I18n.t("annotations.count") + this.props.num_used}</p>;
7✔
100
    let displayToggle = (
101
      <p>
7✔
102
        <a onClick={this.toggle} className="button">
103
          {I18n.t("annotations.usage")}
104
        </a>
105
      </p>
106
    );
107
    if (this.state.details) {
7✔
108
      let annotation_table = (
109
        <Table
5✔
110
          data={this.state.applications}
111
          columns={this.columns}
112
          initialState={{
113
            grouping: ["user"],
114
          }}
115
          columnFilters={this.state.columnFilters}
116
          onColumnFiltersChange={updaterOrValue => {
117
            this.setState(prevState => {
3✔
118
              let newFilters =
119
                typeof updaterOrValue === "function"
3!
120
                  ? updaterOrValue(prevState.columnFilters)
121
                  : updaterOrValue;
122
              return {columnFilters: newFilters};
3✔
123
            });
124
          }}
125
        />
126
      );
127
      return (
5✔
128
        <fieldset>
129
          {numUsed}
130
          {displayToggle}
131
          {annotation_table}
132
        </fieldset>
133
      );
134
    } else {
135
      return (
2✔
136
        <fieldset>
137
          {numUsed}
138
          {displayToggle}
139
        </fieldset>
140
      );
141
    }
142
  }
143
}
144

145
export function makeAnnotationUsagePanel(elem, props) {
146
  const root = createRoot(elem);
×
147
  return root.render(<AnnotationUsagePanel {...props} />);
×
148
}
149

150
export {AnnotationUsagePanel};
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