0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Redmine wikiマクロを作成する方法6(プロジェクトに所属する全てのユーザーのチケット状態の確認)

Last updated at Posted at 2024-12-23

Redmine wikiマクロを作成する方法6(プロジェクトに所属する全てのユーザーのチケット状態の確認)

Redmine Advent Calendar 2024の16日目の記事として作成しました。
image.png

今年のRedmine Advent Calendarに空白が多く残っており、クリスマスが過ぎる前までになんとか空白の日付の記事を書いて、空白の日付を埋めることを優先して記事を作成しました。そのため、濃くない内容の記事になるかもしれませんが、ご容赦ください。
(やっとRedmine Advent Calendar 2024の全ての枠が埋まりました。今年のRedmine Advent Calendar 2024への投稿はこれが最後です。)

完成形

前回のRedmine wikiマクロを作成する方法5(特定のユーザーのチケット状態の確認)では、wikiマクロの引数にユーザーのログインIDを引数にして、該当のユーザーが担当者になっているチケットの状態を確認しました。

image.png

そのため、複数のユーザーがプロジェクトに所属している場合、各ユーザーごとにwikiマクロを指定する必要があり、煩雑さがあった。今回の開発では、下図のように、wikiマクロでプロジェクトIDを引数にして、該当プロジェクトに所属している全てのユーザーのチケット状態を表示します。これにより、各ユーザーごとにwikiマクロを指定する必要がなくなり、かつ、該当プロジェクトのチケット情報のみ表示されるので、前回は該当プロジェクト以外のプロジェクトのチケット情報も表示されてしまい、セキュリティ上の懸念事項があったが、それも解消された。
image.png

Redmine wikiマクロを作成する方法5(特定のユーザーのチケット状態の確認)をベースに開発をしたため、Redmine wikiマクロを作成する方法5(特定のユーザーのチケット状態の確認)で紹介したプログラムソースを流用できる部分は流用している。


背景

Redmineには自作のwikiマクロを作成して登録することができます。
その方法としてはプラグインを作成しますがwikiマクロの登録のためのプラグインは比較的開発が簡単であるため、プラグインを作ったことがない方でも簡単に試してみることができるメリットがあります。

wikiマクロでは色々な処理をすることができるためRedmineの構造を理解したり、Rubyを理解したり、プラグインの仕組みを理解したりするためには良い教材になるかと思います。
今年のRedmine Advent Calendarを通して、何回かに分けてwikiマクロの作り方を紹介したいと思います。

今回の記事では「Redmine wikiマクロを作成する方法6」として「プロジェクトに所属する全てのユーザーのチケット状態の確認」する方法を説明します。

前提条件:

使用するwikiマクロ登録用プラグインはRedmine wikiマクロを作成する方法1で説明したプラグインを使用します。/plugins/wiki_macro_plugin/init.rbの「init.rb」ファイルにwikiマクロを登録します。


1. マクロを実装

  1. /plugins/wiki_macro_plugin/init.rbの「init.rb」ファイルを編集して、Wikiマクロを登録します:
    Redmine::Plugin.register :wiki_macro_plugin do
     省略
    end
    
     Redmine::WikiFormatting::Macros.register do
       desc "Display task lists for all members of a project, including unassigned tasks with task numbers"
       macro :project_members_tasks do |obj, args|
         # プロジェクトの取得
         project = Project.find_by_identifier(args.first || obj.project.identifier)
         return "プロジェクトが見つかりません。" unless project
     
         # プロジェクトメンバーの取得
         members = project.members
         content = "#{project.name}のメンバーとタスク一覧<br>"
     
         # メンバーごとのタスクを収集
         members.each do |member|
           user = member.user
           content << "<h3>#{user.name}のタスク</h3>"
     
           # ユーザーのタスクを取得
           issues = project.issues.where(assigned_to_id: user.id)
           if issues.any?
             content << "<table border='1' style='border-collapse: collapse; width: 100%;'>"
             content << "<tr><th>No</th><th>#</th><th>題名</th><th>開始日</th><th>期日</th><th>状態</th><th>進捗率</th></tr>"
     
             issues.each_with_index do |issue, index|
               days_info = if issue.due_date
                             days_left = (issue.due_date - Date.today).to_i
                             if days_left > 0
                               "期日まで #{days_left}日"
                             elsif days_left == 0
                               "今日が期日"
                             else
                               "<font color='red'>#{days_left.abs}日 遅れ</font>"
                             end
                           else
                             "期日未設定"
                           end
     
               content << "<tr>"
               content << "<td>#{index + 1}</td>"
               content << "<td>#{link_to("##{issue.id}", issue_path(issue))}</td>"
               content << "<td>#{issue.subject}</td>"
               content << "<td>#{issue.start_date || 'N/A'}</td>"
               content << "<td>#{issue.due_date || 'N/A'}</td>"
               content << "<td>#{days_info}</td>"
               content << "<td>#{issue.done_ratio}%</td>"
               content << "</tr>"
             end
     
             content << "</table>"
           else
             content << "タスクがありません。"
           end
         end
     
         # 担当者が未指定のタスク
         unassigned_issues = project.issues.where(assigned_to_id: nil)
         if unassigned_issues.any?
           content << "<h3>担当者未指定</h3>"
           content << "<table border='1' style='border-collapse: collapse; width: 100%;'>"
           content << "<tr><th>No</th><th>#</th><th>題名</th><th>開始日</th><th>期日</th><th>状態</th><th>進捗率</th></tr>"
     
           unassigned_issues.each_with_index do |issue, index|
             days_info = if issue.due_date
                           days_left = (issue.due_date - Date.today).to_i
                           if days_left > 0
                             "期日まで #{days_left}日"
                           elsif days_left == 0
                             "今日が期日"
                           else
                             "<font color='red'>#{days_left.abs}日 遅れ</font>"
                           end
                         else
                           "期日未設定"
                         end
     
             content << "<tr>"
             content << "<td>#{index + 1}</td>"
             content << "<td>#{link_to("##{issue.id}", issue_path(issue))}</td>"
             content << "<td>#{issue.subject}</td>"
             content << "<td>#{issue.start_date || 'N/A'}</td>"
             content << "<td>#{issue.due_date || 'N/A'}</td>"
             content << "<td>#{days_info}</td>"
             content << "<td>#{issue.done_ratio}%</td>"
             content << "</tr>"
           end
     
           content << "</table>"
         end
     
         content.html_safe
       end
     end
    

以下、コードを1行ずつ解説します。


Redmine::WikiFormatting::Macros.register do
  • 説明: Redmineに新しいWikiマクロを登録するための宣言。このブロック内でカスタムマクロを定義します。

  desc "Display task lists for all members of a project, including unassigned tasks with task numbers"
  • 説明: マクロの説明文を設定します。

  macro :project_members_tasks do |obj, args|
  • 説明: :project_members_tasksという名前のWikiマクロを定義します。
  • 引数:
    • obj: 現在のWikiページやプロジェクトなどのコンテキストオブジェクト。
    • args: マクロに渡された引数の配列(プロジェクト識別子を引数とします。)。

    project = Project.find_by_identifier(args.first || obj.project.identifier)
  • 説明: 引数または現在のプロジェクトからプロジェクトを取得します。

    return "プロジェクトが見つかりません。" unless project
  • 説明: プロジェクトが見つからない場合、エラーメッセージを返して処理を終了します。

    members = project.members
  • 説明: 指定されたプロジェクトのメンバー(ユーザー情報を含む)を取得します。

    content = "#{project.name}のメンバーとタスク一覧<br>"
  • 説明: 出力の冒頭に、プロジェクト名を含む見出しを設定します。

    members.each do |member|
  • 説明: プロジェクトの各メンバーについて繰り返し処理を開始します。

      user = member.user
  • 説明: メンバー情報からユーザーオブジェクトを取得します。

      content << "<h3>#{user.name}のタスク</h3>"
  • 説明: メンバーごとにユーザー名を見出しとして表示します。

      issues = project.issues.where(assigned_to_id: user.id)
  • 説明: 指定されたユーザーに割り当てられたプロジェクト内のチケットを取得します。

      if issues.any?
  • 説明: 該当するチケットがある場合、処理を進めます。

        content << "<table border='1' style='border-collapse: collapse; width: 100%;'>"
  • 説明: HTMLテーブルの開始タグを作成します。

        content << "<tr><th>No</th><th>#</th><th>題名</th><th>開始日</th><th>期日</th><th>状態</th><th>進捗率</th></tr>"
  • 説明: テーブルヘッダー行を追加します。列名はタスク番号、ID、題名、開始日、期日、状態、進捗率です。

        issues.each_with_index do |issue, index|
  • 説明: ユーザーのチケットごとに処理を繰り返し、チケットにインデックスを付けます。

          days_info = if issue.due_date
  • 説明: チケットに期日が設定されているかを確認します。

            days_left = (issue.due_date - Date.today).to_i
  • 説明: 今日の日付を基準に、期日までの日数を計算します。

            if days_left > 0
              "期日まで #{days_left}日"
  • 説明: 期日が将来の場合、残りの日数を表示します。

            elsif days_left == 0
              "今日が期日"
  • 説明: 期日が今日の場合、「今日が期日」と表示します。

            else
              "<font color='red'>#{days_left.abs}日 遅れ</font>"
  • 説明: 期日が過ぎている場合、遅延日数を赤字で表示します。

          else
            "期日未設定"
  • 説明: 期日が設定されていない場合、「期日未設定」と表示します。

          content << "<tr>"
  • 説明: HTMLテーブルの新しい行を開始します。

          content << "<td>#{index + 1}</td>"
  • 説明: タスクの番号を表示します(インデックス+1)。

          content << "<td>#{link_to("##{issue.id}", issue_path(issue))}</td>"
  • 説明: チケットIDをリンクとして表示します。

          content << "<td>#{issue.subject}</td>"
  • 説明: チケットの題名を表示します。

          content << "<td>#{issue.start_date || 'N/A'}</td>"
  • 説明: チケットの開始日を表示します。未設定の場合は「N/A」と表示します。

          content << "<td>#{issue.due_date || 'N/A'}</td>"
  • 説明: チケットの期日を表示します。未設定の場合は「N/A」と表示します。

          content << "<td>#{days_info}</td>"
  • 説明: 期日までの残り日数や遅延情報を表示します。

          content << "<td>#{issue.done_ratio}%</td>"
  • 説明: チケットの進捗率をパーセントで表示します。

          content << "</tr>"
  • 説明: HTMLテーブルの行を終了します。

        end
  • 説明: チケットのループ処理を終了します。

        content << "</table>"
  • 説明: HTMLテーブルの終了タグを追加します。

      else
        content << "タスクがありません。"
  • 説明: 該当するチケットがない場合にメッセージを表示します。

    end
  • 説明: メンバーごとのループ処理を終了します。

    unassigned_issues = project.issues.where(assigned_to_id: nil)
  • 説明: 担当者が未設定のチケットを取得します。

    if unassigned_issues.any?
  • 説明: 未割り当てのチケットが存在する場合の処理を進めます。

以降、未割り当てチケットの処理はメンバーごとのチケット処理と同様の形式で進みます。


    content.html_safe
  • 説明: 生成したHTMLをそのまま出力するよう指定します。

  end
end
  • 説明: マクロ定義を終了します。

2. マクロの使い方:

wikiページで下記の形式でwikiマクロを実行します。

 {{project_members_tasks(project_identifier)}}
  • project_identifierにプロジェクトIDを引数として渡します。引数を省略すると現在のwikiが所属しているプロジェクトが引数として渡されます。
    image.png

下図のようにwikiマクロの実行結果が表示されます。
image.png

「#」欄のチケット番号をクリックすると、該当のチケットの詳細ページに移動できます。
image.png


感想

  • wikiマクロ登録用のプラグインがあれば、簡単にwikiマクロを登録できることが分かります。
  • プロジェクトに所属している全てのユーザーが各々担当しているチケットの開始日、期日、状態、進捗率を一覧で確認することができます。
  • プロジェクトに所属している全てのユーザーのチケットの取得など、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/


関連記事(2024年のRedmine Advent Calendarの記事です。)

* Redmine wikiマクロを作成する方法1

* Redmine wikiマクロを作成する方法2(完了チケットの割合をグラフで表示)

* Redmine wikiマクロを作成する方法3(ステータスごとのチケットの割合をグラフで表示)

* Redmine wikiマクロを作成する方法4(ステータスごとのチケットの割合を一つのグラフで表示)

* Redmine wikiマクロを作成する方法5(特定のユーザーのチケット状態の確認)

* Redmine wikiマクロを作成する方法6(プロジェクトに所属する全てのユーザーのチケット状態の確認)

関連記事(2023年のRedmine Advent Calendarの記事です。)

* JqueryでRedmineのメニューにアイコンを入れる方法

* JqueryでRedmineのメニューを閉じたり開いたりする方法

 * JqueryでRedmineの「活動ページ」をもっと便利に(タイトルを開閉したり、曜日を入れたり)

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

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

 * JqueryでRedmineの「チケットページ」をもっと便利に(年ごと、月ごと、四半期ごとの集計機能の開発)

 * RedmineのパスワードやログインIDを忘れた時の復旧方法

 * 「rails console」を使ってRedmine上のスケジュールを一括変更する方法

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?