JqueryでRedmineの「活動ページ」をもっと便利に②(フィルタリング機能と移動機能)

## JqueryでRedmineの「活動ページ」をもっと便利に②(フィルタリング機能と移動機能)

[Redmine Advent Calendar 2023](https://adventar.org/calendars/8974)の11日目の記事として作成しました。

* * *
### 既存のRedmineで不便なこと、改善したい点

必要とする情報を網羅的に全て取得して、そこから確認をしたい情報を絞り込むことで、「探したい」情報、「確認したい」情報に漏れなくアクセスすることができます。そのため、Redmineでは「チケット」、「ガントチャート」、「カレンダー」などのページで「フィルター」機能が提供されています。
Redmineで標準で提供されているフィルター機能はかなり強力で、柔軟な条件で情報の絞り込みを直感的に行うことができます。

<img width="100%" alt="チケットページのフィルター機能" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3633321/4494bc59-e791-eb78-987d-3365baa14052.png">

　　　　　　　　　　　　　　　　　　＜チケットページのフィルター機能＞

しかし、「活動ページ」には柔軟なフィルター機能はなく、サイドバーで、閲覧対象時期の選択、表示ユーザーの選択、表示対象の情報の種別のみ指定することができます。サイドバーで提供している検索機能も一種のフィルター機能といえますが、「活動ページ」にもっと柔軟なフィルター機能を追加できる改善の余地があると思いました。

<img width="100%" alt="活動ページのフィルター機能" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3633321/bcc4f777-38f5-3dbc-eece-ac9e96710b98.png">

　　　　　　　　　　　　　　　　　　＜活動ページのフィルター機能＞

今回、「活動ページ」に、JavaScript（Jquery）だけで、独自のフィルター機能と、各日付のタイトルに簡単に移動できる機能を追加して、Redmineの「活動ページ」をもっと便利に、プチ改造をしてみます。

下図が完成イメージです。サンプル動画のように、
１）トップの位置からマウスで縦スクロールさせる必要なく、各日付タイトルの部分に移動することができます。
２）各日付タイトルごとに移動するボタンに、各日付タイトルに属しているアイテムが何個あるのかを表示します。
３）フィルター用のテキストボックスを追加して、リアルタイムで検索した情報のみを表示します。チケット作成者、チケットのタイトル、チケットのステータスなどを検索対象としており、自由度が高い検索が可能です。

<img width="100%" alt="完成イメージ" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3633321/4b931eaa-b618-74d3-8bf8-135763bb11bb.gif">

　　　　　　　　　＜JqueryでRedmineの「活動ページ」をもっと便利にした画面＞

* * *         
### 実現した方法

#### 下記のプロセスでRedmineの「活動ページ」をもっと便利に改造します。

１）各日付タイトル毎に移動するボタンを追加
２）各日付タイトルごとにトップに戻るボタンを追加
３）検索用のテキストボックスの追加、検索機能の実装

#### 具体的な方法を説明します。

1.1.　各日付タイトル毎に移動するボタンを追加

まずは活動ページの日付の部分の要素を調べます。「#activity > h3」であることがわかります。「#activity > h3」は複数あるので、each関数でループを回します。

<img width="100%" alt="開発対象の要素の確認" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3633321/0057f33b-fa03-bc06-93f2-e2a410ea4b46.png">

　　　　　　　　　＜開発対象の要素の確認＞
         
h3要素に「youso1」、「youso2」のように連番でID名を追加します。ID名を追加することによって、aタグをクリックした時に、同一ページ内での移動が可能になります。
追加したID名をリンク先にするaタグも一緒に作成し、その際、日付のタイトルに属しているアイテムの件数も、「kensu」というクラスのspanタグのテキストとして要素を生成し、最後に、「活動」という文字を修飾しているh2タグの後ろに挿入します。

<img width="100%" alt="件数を表示した各日付タイトル毎に移動するボタンの追加" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3633321/89cffe22-851b-fdee-527e-159d749b09bd.png">

　　　　　　　　　＜件数を表示した各日付タイトル毎に移動するボタンの追加＞

「各日付タイトル毎に移動するボタン」に移動先を指定するだけで、「各日付タイトル毎に移動するボタン」は完成します。使用したソースは下記の通りです。

```JavaScript

  var links = []; // 各h3要素の情報を蓄積する配列

  $("#activity h3").each(function (index) {
    // 連番のIDを作成して付与
    var newID = "youso" + (index + 1);
    $(this).attr("id", newID);

    // 各h3要素の情報を配列に追加
    var linkContent =
      "　<span>" +
      $(this).text() +
      '</span><span class="badge badge-status-open"><a href="#' +
      newID +
      '"><span class="kensu">' +
      $(this).next("dl").find("dt").length +
      "</span>件</a></span>";
    links.push(linkContent);
  });

  links.push("<br><br>");
  // 各h3要素の情報をまとめて追加
  $("h2").after(links.join(""));

```
2.1.　各日付タイトルごとにトップに戻るボタンを追加

「活動」ページが縦に長いため、「各日付タイトル毎に移動するボタン」をクリックするとページの下段に移動して、再度ページのトップまで移動するためには、かなりのスクロール量が必要になる場合があります。この問題を解決するために、「トップに戻る」ボタンを追加します。

<img width="100%" alt="「トップに戻る」ボタン" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3633321/a66bb32c-f010-89c8-d701-2d4601a5ae6f.png">

　　　　　　　　　＜「トップに戻る」ボタン＞

         
使用したソースは下記の通りです。「#content」要素が活動ページのトップになります。
上記の「$("#activity h3").each(function (index) {」のループの部分で各h3タグに「トップに戻る」ボタンを追加します。

```JavaScript
 
     //トップに戻るボタンを追加
    $(this).append(
      '  <span class="badge badge-status-locked"><a href="#content">TOPに戻る</a></span>'
    );
    
 ```


         


3.1.　検索用のテキストボックスの追加

検索用のテキストボックスの追加自体は非常に簡単です。下記の一文だけで実現できます、

```JavaScript

  //検索ボックスの追加
  links.push('<input type="text" id="search_activity">');
  
```

<img width="100%" alt="検索用のテキストボックスの追加" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3633321/598d19e0-8982-0703-a741-fc5669c0940b.png">

　　　　　　　　　　　　　　　＜検索用のテキストボックスの追加＞
               

3.2.　「検索用のテキストボックスの機能の実装①」入力された文字列の取得

上記で検索用のテキストボックスを追加できましたが、テキストボックスに何か値を入れても、このままでは何の反応もしません。検索用のテキストボックスに検索機能を実装する必要があります。
検索用のテキストボックスのinputイベントを監視して、検索用のテキストボックスに文字が入力される時にリアルタイムで、検索用のテキストボックスに入力された文字列を「searchText」という変数で取得します、
使用したソースは下記の通りです。

```JavaScript

  // input要素の変更イベントを監視
  $("#search_activity").on("input", function () {
    // 入力された文字列を取得
    var searchText = $(this).val().toLowerCase();
  }  

```

3.3.　「検索用のテキストボックスの機能の実装②」検索結果の表示

上記で取得した文字列が日付のタイトルに属しているdt要素に含まれていたら表示、含まれていない場合は非表示にします。「toLowerCase」を使用して、検索用のテキストボックスに入力された文字列も、dt要素に含まれている文字列も全て小文字化させて、大文字、小文字を区別しないで検索を可能にします。
検索結果、要素を表示、非表示にさせるのはdt要素だけではなく、隣の要素であるdl要素にも適用する処理をしています。使用したソースは下記の通りです。

```JavaScript

    // 各dl要素をループ処理
    $("#activity dt").each(function () {
      // dl要素内のテキストを取得
      var dlText = $(this).text().toLowerCase();

      // 入力された文字列がdl要素のテキストに含まれているか判定
      var isMatch = dlText.includes(searchText);
      if (isMatch) searchFg = true;
      // 該当のdl要素を表示または非表示にする
      $(this).toggle(isMatch);
      $(this).next().toggle(isMatch);
    });

```

検索対象は、チケット作成者、チケットのタイトル、チケットのステータスなど自由度が高い検索が可能です。
下図の例でチケット作成者、チケットのステータスで検索ができていることが確認できます。

<img width="100%" alt="検索用のテキストボックスの追加" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3633321/e6b231d9-3ccf-0360-c6c0-0d06e1932a32.png">

　　　　　　　　　　　　　　　＜検索用のテキストボックスの追加＞

3.4. 検索後の件数を「各日付タイトル毎に移動するボタン」に反映させる

「各日付タイトル毎に移動するボタン」には「日付のタイトルに属しているアイテムの件数」が表示されていますが、検索テキストボックスに値を入れると、表示されている「日付のタイトルに属しているアイテムの件数」が変動します。そのため、検索テキストボックスに値を入れると、リアルタイムで「日付のタイトルに属しているアイテムの件数」を取得して表示させる必要があります。

下記は該当のソースですが、「:visible」という状態の「dt」要素の数を集計して、「kensu」クラスの要素のテキストの部分に値を更新すれば実現できます。

```JavaScript

    //検索後の件数（表示要素の数）を反映させる
    $("#activity h3").each(function (index) {
      $(".kensu").eq(index).text($(this).next("dl").find("dt:visible").length);
    });
```

下図のように、検索結果に応じて、日付のタイトルに属しているアイテムの件数がリアルタイムに反映できていることがわかります。

<img width="100%" alt="検索後の表示要素の件数をリアルタイムで変更" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3633321/39552bf6-d474-b5fb-2949-369e6bfbdcf6.png">

　　　　　　　　　　　　　　　＜検索後の表示要素の件数をリアルタイムで変更＞
               

4.上記のJqueryのスクリプトを実行する方法は色々とありますが、[View Customize](https://github.com/onozaty/redmine-view-customize/blob/master/README.ja.md)がインストールされていれば、一番簡単にJqueryを適用できます。


* * *
### 感想






* 前回紹介した[JqueryでRedmineの「活動ページ」をもっと便利に(タイトルを開閉したり、曜日を入れたり)](https://qiita.com/yam_asaki/items/718513b52b30b30f65bc)では、Redmineの「活動ページ」が縦長で、縦スクロールをする煩雑さを解決する方法として、タイトルを開閉する方法にチャレンジをしました。
* 今回は同じ課題に対して、aタグで確認をしたい日付に移動をする方法と、検索フィルタリング機能で不要な情報をページに表示をしないことで縦スクロールの最小化にチャレンジをしました。
* 検索フィルタリング機能は検索ボックスに検索したい文字を入力するだけで、リアルタイムで検索可能なため、「検索文字を入力」＋「検索ボタンをクリック」のような２つのアクションを必要としないので、ストレスなく検索をすることができました。
* チケット作成者、チケットのタイトル、チケットのステータスなどを横断的に検索対象としており、チケット作成者検索用のテキストボックス、チケットのタイトル検索用のテキストボックスのように、検索用のテキストボックスが別々に分かれていないため、検索対象を事前に考慮することなく、気になるキーワードで検索をすれば関連する情報が表示されます。
* プラグインやテーマをインストールする必要がない為に、Redmineのサーバー上でファイルの追加などをする必要がなく、サーバー上のファイルを変更するアクセス権限がない場合でも、手軽にRedmineのプチ改造が可能になります。

* * *
#### この記事の作成者の紹介
* * *
山崎進
* Redmine、Jquery、JavaScript,Rails、Ruby、SQL、VBA、RPAの開発を行なっています。
* 自動化、業務の効率化に高い関心があります。
* 下記の媒体で情報を発信しています。Redmineのプラグインの開発などに対応が可能ですので、お気軽にご連絡ください。

　* Qiita：https://qiita.com/ankosoft
　* Twitter：https://twitter.com/yamasaki24
　* Redmine Advent Calendarで記事投稿
　* redmine.tokyoで講演多数
　* Redmine Japan Vol.1 前夜祭、Redmine Japan Vol.3で講演
　* https://ankosoft.co.jp/blog/
　* https://technology.ankosoft.co.jp/

* * *
### 関連記事

 *　[JqueryでRedmineのメニューにアイコンを入れる方法](https://qiita.com/yam_asaki/items/32097598cb0a653dd916)

 *　[JqueryでRedmineのメニューを閉じたり開いたりする方法](https://qiita.com/yam_asaki/items/5ac4a1127beeed53059c)

　*　[JqueryでRedmineの「活動ページ」をもっと便利に(タイトルを開閉したり、曜日を入れたり)](https://qiita.com/yam_asaki/items/718513b52b30b30f65bc)

　*　[JqueryでRedmineの「活動ページ」をもっと便利に②(フィルタリング機能と移動機能)](https://qiita.com/yam_asaki/items/2428610fd89bc73ce0ab)

　*　[JqueryでRedmineの「wikiページ」をもっと便利に(フィルタリング機能と移動機能)](https://qiita.com/yam_asaki/items/a6a32c45dbbc72a28836)

　*　[JqueryでRedmineの「チケットページ」をもっと便利に(年ごと、月ごと、四半期ごとの集計機能の開発)](https://qiita.com/yam_asaki/items/176d07588793b3e66b5d)

　*　[RedmineのパスワードやログインIDを忘れた時の復旧方法](https://qiita.com/yam_asaki/items/6881c92b30dc85f589ad)

　*　[「rails console」を使ってRedmine上のスケジュールを一括変更する方法](https://qiita.com/yam_asaki/items/1d41dc8653773f3522e6)