Implement Redmine Project Menu Item Customize Setting with Plugin

主要是想試試看Redmine這類有時代背景的產品
是否因為Rails與本身設計的彈性
讓開發者易於修改、以及使用者客製化的維度等等
找了不少關鍵字,沒看到我想要的,於是就記錄一下~
  • 實作目標:讓各個專案管理者自行決定某個專案標籤是否顯示,而非關閉此功能
  • 實作範圍:Plugin。不含既有非模組化的Menu item,如:概觀(Overview)、活動(Activity)
  • 示範模組:Redmine Hearts Plugin
  • Redmine原始碼參考 Mirror site
  • 精要結果:修改hearts模組的init.rb即可
    修改後的程式碼如下
    menu :project_menu, :hearts, { :controller => :hearts, :action => :index },
      :param => :project_id,
      :caption => :hearts_link_label,
      # 如果hearts模組在project是enable的,才產生此menu item
      :if => proc { |project| project.module_enabled? :hearts }
    # 在Project新增此模組的設定檔,也有權限限制,只有專案管理員可設定。
    project_module :hearts do
      permission :hearts, { hearts: [:index] }, require: :member
    end 
    
    只需修改這樣,就可以達到上述客製化的設定,相當精美而且直覺
  • 細部說明:
    由於所有Redmine模組的init.rb都是透過Redmine::Plugin實作
    與此次案例有關的程式碼為menu
    裡頭也引用到Redmine::MenuManager.map,會將Menu Item的資訊存入
    很明顯的,在這個步驟並沒有觸發:if判斷的Proc程式碼區段
    那麼是在哪裡被啟用呢?
    在 layouts/base.html.rb,如果目前是在Project頁面
    那麼就會呼叫 MenuManager的render_main_menu方法
    在往裡頭追縱會看到menu_manager.rb MenuItem::allow? 方法裏頭這段程式碼
    if condition && !condition.call(project)
        # Condition that doesn't pass
        return false
    end
    
    這個call,就是proc被啟動的時間點,同時還傳了當下的project物件
    所以我們就可以拿到這個物件相關的資訊,用以判斷模組在該project是否啟用
    這段程式碼就在這裡生效了
    :if => proc { |project| project.module_enabled? :hearts }
    
    當proc最後回傳true的時候就顯示,反之則跳過
  • Demo
    1. 到該專案點選設定
    2. 取消Hearts並儲存,此時『讚』標籤已消失
    3. 議題的讚功能都還在,正常運作
    4. 不會影響到其他專案,證明是依專案設定而非全域設定
未來如果要更彈性設定模組哪些功能要開、哪些要關,可以參考現有Plugin專案設定作法
由於很多服務都是關掉就整個功能沒了,為了這個再開個標籤只有一個設定也有點多餘
我們是嘗試僅關閉部分顯示邏輯,也看到Rails與Redmine的彈性

留言