Redmineのカスタムフィールドに＋１ボタン的なものを追加する

人生で初めてAdvent Calendarを書いてみました。

# 背景

バグや要望などの管理で使用していますが、カスタムフィールドで要望者数なるものがあり、対応して欲しい人はそこの値をカウントアップさせる、という運用が存在していました。
「カウントアップするボタン欲しいよね」ってことで、ちょっとやってみました。
残念ながらSNSなどとは連携できない上に、プラグインも気軽に入れられないようなクローズドな環境でしたが、元々入っていたView Customize Pluginならできるだろうと思ったので、こちらを使います。
Qiitaにもたくさん先人達の知恵があったので参考にさせていただきました。

[View-Customize公式](https://github.com/onozaty/redmine-view-customize)
[Redmineのプラグイン「view customize plugin」のカスタマイズ例](https://qiita.com/wfigo7/items/f13a89e1d3522f4a73b6)

#環境

Redmine view customize pluginの動作を手元ですぐに確認したいので、MacでDockerを使ってRedmineの環境を構築しておきます。

#Docker　for　Mac

[公式](https://docs.docker.com/docker-for-mac/)を確認して、インストールした後は以下のコマンドを実行していって環境を構築しておきます。

```
# イメージのダウンロード
docker pull redmine
#　コンテナの起動
docker run -p 3000:3000 --name redmine redmine
#　ログイン
docker exec -it redmine bash
#　プラグインのインストール
git clone https://github.com/onozaty/redmine-view-customize.git plugins/view_customize
rake redmine:plugins:migrate
exit
# 再起動
docker restart redmine
```
これで http://localhost:3000 にアクセスすればプラグインが入った状態になっています（初期ユーザはadmin/admin）。

#ボタン追加してみる

運用上、必ず注記に一言書くことが習慣になっていたので、編集画面で開いたところに追加してみます。
Chromeなどで追加したいカスタムフィールドからセレクタをコピーして追加します。
とりあえずカスタムフィールドのIDは適当です。

```
$(function() {
  var label = $('#attributes > div:nth-child(2) > div.splitcontentleft > p > label');
  var btn = '<button type="button" class="count_up_btn">+1</button>';
  label.append(btn);

  $('.count_up_btn').on('click', function () {
    var field = $('#issue_custom_field_values_1');
    field.val(Number(field.val()) + 1);
  });
});

```
こうするとボタンが表示されました。

![スクリーンショット 2017-12-16 16.22.19.png](https://qiita-image-store.s3.amazonaws.com/0/29845/64e422c8-a5f1-2b0f-e02d-f1dea6d3ea1a.png)


#トラッカーや優先度を変えるとボタンが消えてしまう

どうやらトラッカーや優先度を変えると、DOMの書き換えなどが発生して消えてしまうようです。
とりあえずAjaxの処理が終わったあとにもう一回ボタン追加処理を実行してみます。

```
$(function() {
  count_up_btn();

  $(document).ajaxComplete(function(){
    count_up_btn();
  });
});
```

これでトラッカーやステータスを変更してもボタンは消えなくなりました。

#テキストフィールドではなくラベルにしてしまう

１ユーザ1カウントになっているわけではありません（例えばサポートから「ユーザの〇〇や△△から要望あったよー」となると２カウントアップしたい）。
そのため、~~いつまでの放置されているチケットに対してついつい~~＋１００とか入力されてしまわないように、テキストフィールドからラベルに変えてしまいます（連打されてしまえば同じですが…）。


```
function count_up_btn() {
  var field = $('#issue_custom_field_values_1');
  field.hide(); // テキストフィールドを非表示にする

  var btn = '<button type="button" class="count_up_btn">+1</button>';
  field.after(btn);　
  
  var count = '<span class="issue_custom_field_values_1_label">'+ field.val() +'</span>';
  $('.count_up_btn').after(count)

  $('.count_up_btn').on('click', function () {
    var label = $('.issue_custom_field_values_1_label');
    var num = Number(field.val()) + 1;
    field.val(num); // 元々のテキストフィールドの値も更新する
    label.text(num);
  });
}
```

こんな感じになります。

![スクリーンショット 2017-12-16 16.56.39.png](https://qiita-image-store.s3.amazonaws.com/0/29845/b4372d5f-84c2-c261-ae34-d2fa32be5457.png)


#カウントダウンもする

同じ要領で間違ってしまった場合の"-1"ボタンも付けておきます。

```
$(function() {
  count_up_down();
  
  $(document).ajaxComplete(function(){
    count_up_down();
  });
});

function count_up_down() {
  var field = $('#issue_custom_field_values_1');
  field.hide();

  var minus_btn = '<button type="button" class="count_down_btn">-1</button>';
  field.after(minus_btn);

  var plus_btn = '<button type="button" class="count_up_down">+1</button>';
  $('.count_down_btn').after(plus_btn);
  
  var count = '<span class="issue_custom_field_values_1_label">'+ field.val() +'</span>';
  $('.count_up_down').after(count)

  $('.count_up_down').on('click', function () {
    var label = $('.issue_custom_field_values_1_label');
    var num = Number(field.val()) + 1;
    field.val(num);
    label.text(num);
  });

  $('.count_down_btn').on('click', function () {
    var label = $('.issue_custom_field_values_1_label');
    var num = Number(field.val()) - 1;
    field.val(num);
    label.text(num);
  });
}
```

こんな感じになります。

![スクリーンショット 2017-12-16 17.10.08.png](https://qiita-image-store.s3.amazonaws.com/0/29845/994b4455-51d9-6773-86f0-ffe15ad3655a.png)

#　まとめ

ここまでのものは[ここ](https://github.com/ktanaha/redmine-view-customize-sample/blob/master/plus-one.js)にあります。~~あとはこれをどうやってクローズドな環境に持っていくか…~~

雑な感じですが、Docker使えばview customize pluginの動作もすぐに確認できる環境つくれるので良かったです。
こういう環境があればプラグインの開発なんかもすぐにできそうなので、RubyやRailsの知識自体がほぼありませんが、何かしら作ってみたいところです。