[Notice] Announcing the End of Demo Server [Read me]
HeeGu Lee 2014-07-02
Shows or hides menus on projects according to menu settings.
* Requirements:

There is VOC to want to shows and hides menus on projects.

* Solutions:

When creating projects and change project settings, users can configure menu settings to show or hides.

Menus which can be configured are `Code`, `Issue`, `Pull Request`, `Review`, `Milestone` and `Board`.

After creating projects, only `Project Manager` can configure menu settings.

Private-issue: 601
@67a21e777be236e14b89401df3e5ab983b0bfb17
app/controllers/ImportApp.java
--- app/controllers/ImportApp.java
+++ app/controllers/ImportApp.java
@@ -20,11 +20,7 @@
  */
 package controllers;
 
-import models.Organization;
-import models.OrganizationUser;
-import models.Project;
-import models.ProjectUser;
-import models.User;
+import models.*;
 import models.enumeration.RoleType;
 import play.data.Form;
 import play.db.ebean.Transactional;
@@ -97,6 +93,8 @@
 
             Long projectId = Project.create(project);
 
+            saveProjectMenuSetting(project);
+
             if (User.isLoginIdExist(owner)) {
                 ProjectUser.assignRole(UserApp.currentUser().id, projectId, RoleType.MANAGER);
             }
@@ -119,6 +117,21 @@
         }
     }
 
+    private static void saveProjectMenuSetting(Project project) {
+        Form<ProjectMenuSetting> filledUpdatedProjectMenuSettingForm = form(ProjectMenuSetting.class).bindFromRequest();
+        ProjectMenuSetting updatedProjectMenuSetting = filledUpdatedProjectMenuSettingForm.get();
+
+        project.refresh();
+        updatedProjectMenuSetting.project = project;
+
+        if (project.menuSetting == null) {
+            updatedProjectMenuSetting.save();
+        } else {
+            updatedProjectMenuSetting.id = project.menuSetting.id;
+            updatedProjectMenuSetting.update();
+        }
+    }
+
     /**
      * Add assorted error messages from TransportException like Unauthorized(401), Forbidden(403)
      * or other transport error with HTTP response code to the given form.
app/controllers/ProjectApp.java
--- app/controllers/ProjectApp.java
+++ app/controllers/ProjectApp.java
@@ -204,6 +204,9 @@
         }
         ProjectUser.assignRole(user.id, Project.create(project), RoleType.MANAGER);
         RepositoryService.createRepository(project);
+
+        saveProjectMenuSetting(project);
+
         return redirect(routes.ProjectApp.project(project.owner, project.name));
     }
 
@@ -276,9 +279,27 @@
         }
 
         updatedProject.update();
+
+        saveProjectMenuSetting(updatedProject);
+
         return redirect(routes.ProjectApp.settingForm(ownerId, updatedProject.name));
     }
 
+    private static void saveProjectMenuSetting(Project project) {
+        Form<ProjectMenuSetting> filledUpdatedProjectMenuSettingForm = form(ProjectMenuSetting.class).bindFromRequest();
+        ProjectMenuSetting updatedProjectMenuSetting = filledUpdatedProjectMenuSettingForm.get();
+
+        project.refresh();
+        updatedProjectMenuSetting.project = project;
+
+        if (project.menuSetting == null) {
+            updatedProjectMenuSetting.save();
+        } else {
+            updatedProjectMenuSetting.id = project.menuSetting.id;
+            updatedProjectMenuSetting.update();
+        }
+    }
+
     private static boolean validateWhenUpdate(String loginId, Form<Project> updateProjectForm) {
         Long id = Long.parseLong(updateProjectForm.field("id").value());
         String name = updateProjectForm.field("name").value();
app/controllers/PullRequestApp.java
--- app/controllers/PullRequestApp.java
+++ app/controllers/PullRequestApp.java
@@ -187,8 +187,9 @@
 
     private static Project getSelectedProject(Project project, String projectId, boolean isToProject) {
         Project selectedProject = project;
-        if(isToProject && project.isForkedFromOrigin()) {
-            selectedProject = project.originalProject;
+        if(isToProject && project.isForkedFromOrigin() && project.originalProject.menuSetting.code
+                && project.originalProject.menuSetting.pullRequest) {
+                selectedProject = project.originalProject;
         }
 
         if(StringUtils.isNumeric(projectId)) {
app/models/Project.java
--- app/models/Project.java
+++ app/models/Project.java
@@ -126,6 +126,9 @@
     @Enumerated(EnumType.STRING)
     public ProjectScope projectScope;
 
+    @OneToOne(mappedBy = "project", cascade = CascadeType.ALL)
+    public ProjectMenuSetting menuSetting;
+
     /**
      * @see {@link User#SITE_MANAGER_ID}
      * @see {@link RoleType#SITEMANAGER}
@@ -668,6 +671,10 @@
         copyProject.vcs = project.vcs;
         copyProject.owner = owner;
         copyProject.projectScope = project.projectScope;
+        copyProject.menuSetting = new ProjectMenuSetting(project.menuSetting);
+        copyProject.menuSetting.project = copyProject;
+        copyProject.menuSetting.save();
+
         return copyProject;
     }
 
@@ -707,8 +714,9 @@
         List<Project> projects = new ArrayList<>();
         projects.add(this);
         projects.addAll(forkingProjects);
-        if(isForkedFromOrigin()) {
-            projects.add(originalProject);
+        if(isForkedFromOrigin() && originalProject.menuSetting.code
+                && originalProject.menuSetting.pullRequest) {
+                projects.add(originalProject);
         }
         return projects;
     }
 
app/models/ProjectMenuSetting.java (added)
+++ app/models/ProjectMenuSetting.java
@@ -0,0 +1,51 @@
+/**
+ * Yobi, Project Hosting SW
+ *
+ * Copyright 2014 NAVER Corp.
+ * http://yobi.io
+ *
+ * @Author Lee HeeGu
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package models;
+
+import play.db.ebean.Model;
+
+import javax.persistence.*;
+
+@Entity
+public class ProjectMenuSetting extends Model {
+    private static final long serialVersionUID = 1L;
+    public static Finder<Long, ProjectMenuSetting> finder = new Finder<>(Long.class, ProjectMenuSetting.class);
+
+    @Id
+    public Long id;
+    @OneToOne
+    public Project project;
+    public boolean code;
+    public boolean issue;
+    public boolean pullRequest;
+    public boolean review;
+    public boolean milestone;
+    public boolean board;
+
+    public ProjectMenuSetting(ProjectMenuSetting projectMenuSetting) {
+        this.code = projectMenuSetting.code;
+        this.issue = projectMenuSetting.issue;
+        this.pullRequest = projectMenuSetting.pullRequest;
+        this.review = projectMenuSetting.review;
+        this.milestone = projectMenuSetting.milestone;
+        this.board = projectMenuSetting.board;
+    }
+}
app/views/board/list.scala.html
--- app/views/board/list.scala.html
+++ app/views/board/list.scala.html
@@ -102,9 +102,11 @@
 			"nTotalPages" : @page.getTotalPageCount
 		});
 
-		yobi.ShortcutKey.setKeymapLink({
-		   "N": "@routes.BoardApp.newPostForm(project.owner, project.name)"
-		});
+        @if(project.menuSetting.board) {
+            yobi.ShortcutKey.setKeymapLink({
+                "N": "@routes.BoardApp.newPostForm(project.owner, project.name)"
+            });
+        }
 	});
 </script>
 }
app/views/board/view.scala.html
--- app/views/board/view.scala.html
+++ app/views/board/view.scala.html
@@ -128,8 +128,10 @@
 
         // yobi.ShortcutKey
         yobi.ShortcutKey.setKeymapLink({
-            "N": "@routes.BoardApp.newPostForm(project.owner, project.name)",
             "L": "@urlToPostings"
+            @if(project.menuSetting.board) {
+            ,"N": "@routes.BoardApp.newPostForm(project.owner, project.name)"
+            }
             @if(isAllowed(UserApp.currentUser(), post.asResource(), Operation.UPDATE)){
            ,"E": "@routes.BoardApp.editPostForm(project.owner, project.name, post.getNumber)"
             }
app/views/issue/create.scala.html
--- app/views/issue/create.scala.html
+++ app/views/issue/create.scala.html
@@ -83,7 +83,7 @@
                     </dl>
                     }
 
-                    @if(isProjectResourceCreatable(UserApp.currentUser(), project, ResourceType.ISSUE_MILESTONE)) {
+                    @if(project.menuSetting.milestone && isProjectResourceCreatable(UserApp.currentUser(), project, ResourceType.ISSUE_MILESTONE)) {
                         <dl id="milestoneOption" class="issue-option">
                             <dt>@Messages("milestone")</dt>
                             <dd>
app/views/issue/edit.scala.html
--- app/views/issue/edit.scala.html
+++ app/views/issue/edit.scala.html
@@ -104,7 +104,7 @@
                     </dl>
                     }
 
-                    @if(isAllowed(UserApp.currentUser(), issue.milestoneAsResource(), Operation.UPDATE)){
+                    @if(project.menuSetting.milestone && isAllowed(UserApp.currentUser(), issue.milestoneAsResource(), Operation.UPDATE)){
                     <dl id="milestoneOption" class="issue-option">
                         <dt>@Messages("milestone")</dt>
                         <dd>
app/views/issue/my_partial_list.scala.html
--- app/views/issue/my_partial_list.scala.html
+++ app/views/issue/my_partial_list.scala.html
@@ -18,7 +18,7 @@
 * See the License for the specific language governing permissions and
 * limitations under the License.
 **@
-@(issueList:Collection[Issue], searchCondition:models.support.SearchCondition, pageIndex:Int, totalPageCount:Int)
+@(issueList:Collection[Issue], searchCondition:models.support.SearchCondition, pageIndex:Int, totalPageCount:Int, project:Project)
 @import java.util
 @import utils.JodaDateUtil
 @import utils.TemplateHelper._
@@ -89,7 +89,7 @@
                 }
             </div>
             <div class="pull-right">
-                @if(issue.milestone != null) {
+                @if(project.menuSetting.milestone && issue.milestone != null) {
                     <div class="mileston-tag">
                         <a href="@routes.MilestoneApp.milestone(issue.project.owner, issue.project.name, issue.milestone.id)" data-toggle="tooltip" data-placement="top" title="@Messages("milestone")">
                         @issue.milestone.title
app/views/issue/my_partial_search.scala.html
--- app/views/issue/my_partial_search.scala.html
+++ app/views/issue/my_partial_search.scala.html
@@ -116,7 +116,7 @@
 			}
 		</div>
 
-            @my_partial_list(currentPage.getList, param, currentPage.getPageIndex, currentPage.getTotalPageCount)
+            @my_partial_list(currentPage.getList, param, currentPage.getPageIndex, currentPage.getTotalPageCount, project)
 
             <div class="pull-left" style="padding:10px;">
             </div>
app/views/issue/partial_list.scala.html
--- app/views/issue/partial_list.scala.html
+++ app/views/issue/partial_list.scala.html
@@ -93,7 +93,7 @@
                 }
             </div>
             <div class="pull-right">
-                @if(issue.milestone != null) {
+                @if(project.menuSetting.milestone && issue.milestone != null) {
                     <div class="mileston-tag">
                         <a href="@routes.MilestoneApp.milestone(project.owner, project.name, issue.milestone.id)" data-toggle="tooltip" data-placement="top" title="@Messages("milestone")">
                         @issue.milestone.title
app/views/issue/partial_massupdate.scala.html
--- app/views/issue/partial_massupdate.scala.html
+++ app/views/issue/partial_massupdate.scala.html
@@ -95,6 +95,7 @@
             </ul>
         </div>
 
+        @if(project.menuSetting.milestone) {
         <div id="milestone" class="btn-group" data-name="milestone.id">
             <button class="btn dropdown-toggle medium" data-toggle="dropdown" disabled="disabled">
                 <span class="d-label">@Messages("issue.update.milestone")</span>
@@ -108,6 +109,7 @@
                 }
             </ul>
         </div>
+        }
 
         <div id="attaching-label" class="btn-group" data-name="attachingLabel[0].id">
             <button class="btn dropdown-toggle medium" data-toggle="dropdown" disabled="disabled">
app/views/issue/partial_search.scala.html
--- app/views/issue/partial_search.scala.html
+++ app/views/issue/partial_search.scala.html
@@ -141,6 +141,7 @@
                         </dd>
                     </dl>
 
+                    @if(project.menuSetting.milestone) {
                     <dl class="issue-option">
                         <dt>@Messages("milestone")</dt>
                         <dd>
@@ -175,6 +176,7 @@
                             </select>
                         </dd>
                     </dl>
+                    }
                 </div>
 
                 <hr>
@@ -259,9 +261,11 @@
                 });
 
                 // ShortcutKey
-                yobi.ShortcutKey.setKeymapLink({
-                    "N": "@routes.IssueApp.newIssueForm(project.owner, project.name)"
-                });
+                @if(project.menuSetting.issue) {
+                    yobi.ShortcutKey.setKeymapLink({
+                        "N": "@routes.IssueApp.newIssueForm(project.owner, project.name)"
+                    });
+                }
             });
         </script>
         </div>
app/views/issue/view.scala.html
--- app/views/issue/view.scala.html
+++ app/views/issue/view.scala.html
@@ -156,6 +156,7 @@
                         @**<!-- // -->**@
 
                         @**<!-- milestones -->**@
+                        @if(project.menuSetting.milestone) {
                         <dl>
                             <dt>@Messages("milestone")</dt>
                             <dd style="padding:5px 10px;">
@@ -202,6 +203,7 @@
                             }
                             </dd>
                         </dl>
+                        }
                         @**<!-- // -->**@
 
                         @**<!-- labels -->**@
@@ -363,8 +365,10 @@
 
         // yobi.ShortcutKey
         yobi.ShortcutKey.setKeymapLink({
-            "N": "@routes.IssueApp.newIssueForm(project.owner, project.name)",
             "L": "@urlToIssues"
+            @if(project.menuSetting.issue) {
+            ,"N": "@routes.IssueApp.newIssueForm(project.owner, project.name)"
+            }
             @if(isAllowed(UserApp.currentUser(), issue.asResource(), Operation.UPDATE)) {
            ,"E": "@routes.IssueApp.editIssueForm(project.owner, project.name, issue.getNumber)"
             }
app/views/milestone/list.scala.html
--- app/views/milestone/list.scala.html
+++ app/views/milestone/list.scala.html
@@ -145,11 +145,13 @@
         }
     </div>
 </div>
+@if(project.menuSetting.milestone) {
 <script type="text/javascript">
-    $(document).ready(function() {
+    $(document).ready(function () {
         yobi.ShortcutKey.setKeymapLink({
-           "N": "@routes.MilestoneApp.newMilestoneForm(project.owner, project.name)"
+            "N": "@routes.MilestoneApp.newMilestoneForm(project.owner, project.name)"
         });
     });
 </script>
 }
+}
app/views/project/create.scala.html
--- app/views/project/create.scala.html
+++ app/views/project/create.scala.html
@@ -163,6 +163,32 @@
               }
             </div>
           </div>
+          <hr>
+          <!-- Menu Setting -->
+          <div class="row-fluid">
+            <div class="span2 right-txt">
+              @Messages("project.menu.setting")
+            </div>
+            <div class="span10">
+                <input type="checkbox" class="radio-btn" id="menuSettingCode" name="code" value="true" checked="checked">
+                <label for="menuSettingCode" class="bg-radiobtn label-public">@Messages("menu.code")</label>
+                &nbsp;&nbsp;&nbsp;
+                <input type="checkbox" class="radio-btn" id="menuSettingIssue" name="issue" value="true" checked="checked">
+                <label for="menuSettingIssue" class="bg-radiobtn label-public">@Messages("menu.issue")</label>
+                &nbsp;&nbsp;&nbsp;
+                <input type="checkbox" class="radio-btn" id="menuSettingPullRequest" name="pullRequest" value="true" checked="checked">
+                <label for="menuSettingPullRequest" class="bg-radiobtn label-public">@Messages("menu.pullRequest")</label>
+                &nbsp;&nbsp;&nbsp;
+                <input type="checkbox" class="radio-btn" id="menuSettingReview" name="review" value="true" checked="checked">
+                <label for="menuSettingReview" class="bg-radiobtn label-public">@Messages("menu.review")</label>
+                &nbsp;&nbsp;&nbsp;
+                <input type="checkbox" class="radio-btn" id="menuSettingMilestone" name="milestone" value="true" checked="checked">
+                <label for="menuSettingMilestone" class="bg-radiobtn label-public">@Messages("milestone")</label>
+                &nbsp;&nbsp;&nbsp;
+                <input type="checkbox" class="radio-btn" id="menuSettingBoard" name="board" value="true" checked="checked">
+                <label for="menuSettingBoard" class="bg-radiobtn label-public">@Messages("menu.board")</label>
+            </div>
+          </div>
           <!-- // -->
         </div>
 
app/views/project/home.scala.html
--- app/views/project/home.scala.html
+++ app/views/project/home.scala.html
@@ -51,10 +51,12 @@
                     </form>
                 </div>
             </div>
-            <div class="project-clone-wrap span3">
-                <input type="text" class="project-clone-url" id="cloneURL" readonly="readonly" value="@if(project.isGit){@CodeApp.getURLWithLoginId(project)} else {@CodeApp.getURL(project)}">
-                <button class="ybtn project-clone-button" id="cloneURLBtn">@Messages("code.copyUrl")</button>
-            </div>
+            @if(project.menuSetting.code) {
+                <div class="project-clone-wrap span3">
+                    <input type="text" class="project-clone-url" id="cloneURL" readonly="readonly" value="@if(project.isGit){@CodeApp.getURLWithLoginId(project)} else {@CodeApp.getURL(project)}">
+                    <button class="ybtn project-clone-button" id="cloneURLBtn">@Messages("code.copyUrl")</button>
+                </div>
+            }
         </div>
         <div class="row-fluid">
             <div class="span9">
@@ -102,20 +104,26 @@
             <div class="span3">
                 <div class="bubble-wrap gray project-home">
                     <div class="project-btn-wrap">
-                        <span class="project-btn-item">
-                            <a href="@routes.IssueApp.newIssueForm(project.owner, project.name)" class="ybtn ybtn-success">@Messages("button.newIssue")</a>
-                        </span>
-                        @if(project.vcs.equals("GIT")){
-                        <span class="project-btn-item">
-                            <a href="@routes.PullRequestApp.newFork(project.owner, project.name)" class="ybtn ybtn-inverse">
-                                @Messages("fork")
-                            </a>
-                        </span>
+                        @if(project.menuSetting.issue) {
+                            <span class="project-btn-item">
+                                <a href="@routes.IssueApp.newIssueForm(project.owner, project.name)" class="ybtn ybtn-success">@Messages("button.newIssue")</a>
+                            </span>
+                        }
+                        @if(project.menuSetting.code) {
+                            @if(project.vcs.equals("GIT")){
+                            <span class="project-btn-item">
+                                <a href="@routes.PullRequestApp.newFork(project.owner, project.name)" class="ybtn ybtn-inverse">
+                                    @Messages("fork")
+                                </a>
+                            </span>
+                            }
                         }
                     </div>
-                    @defining(Milestone.findOpenMilestones(project.id)){ milestones =>
-                        @if(milestones.length > 0){
-                            @views.html.milestone.partial_status(milestones(0), project)
+                    @if(project.menuSetting.milestone) {
+                        @defining(Milestone.findOpenMilestones(project.id)){ milestones =>
+                            @if(milestones.length > 0){
+                                @views.html.milestone.partial_status(milestones(0), project)
+                            }
                         }
                     }
 
app/views/project/importing.scala.html
--- app/views/project/importing.scala.html
+++ app/views/project/importing.scala.html
@@ -184,6 +184,33 @@
             </div>
           </div>
           <!-- // -->
+            <hr>
+            <!-- VCS -->
+            <div class="row-fluid">
+                <div class="span2 right-txt">
+                    @Messages("project.menu.setting")
+                </div>
+                <div class="span10 cu-desc">
+                    <input type="checkbox" class="radio-btn" id="menuSettingCode" name="code" value="true" checked="checked">
+                    <label for="menuSettingCode" class="bg-radiobtn label-public">@Messages("menu.code")</label>
+                    &nbsp;&nbsp;&nbsp;
+                    <input type="checkbox" class="radio-btn" id="menuSettingIssue" name="issue" value="true" checked="checked">
+                    <label for="menuSettingIssue" class="bg-radiobtn label-public">@Messages("menu.issue")</label>
+                    &nbsp;&nbsp;&nbsp;
+                    <input type="checkbox" class="radio-btn" id="menuSettingPullRequest" name="pullRequest" value="true" checked="checked">
+                    <label for="menuSettingPullRequest" class="bg-radiobtn label-public">@Messages("menu.pullRequest")</label>
+                    &nbsp;&nbsp;&nbsp;
+                    <input type="checkbox" class="radio-btn" id="menuSettingReview" name="review" value="true" checked="checked">
+                    <label for="menuSettingReview" class="bg-radiobtn label-public">@Messages("menu.review")</label>
+                    &nbsp;&nbsp;&nbsp;
+                    <input type="checkbox" class="radio-btn" id="menuSettingMilestone" name="milestone" value="true" checked="checked">
+                    <label for="menuSettingMilestone" class="bg-radiobtn label-public">@Messages("milestone")</label>
+                    &nbsp;&nbsp;&nbsp;
+                    <input type="checkbox" class="radio-btn" id="menuSettingBoard" name="board" value="true" checked="checked">
+                    <label for="menuSettingBoard" class="bg-radiobtn label-public">@Messages("menu.board")</label>
+                </div>
+            </div>
+            <!-- // -->
         </div>
 
         <div class="actions mt20">
app/views/project/partial_dashboard.scala.html
--- app/views/project/partial_dashboard.scala.html
+++ app/views/project/partial_dashboard.scala.html
@@ -26,32 +26,40 @@
 <div class="content-container nm">
     <div class="project-overview-home row-fluid">
         <div class="span6">
-            <h5>@Messages("project.dashboard.openIssuesByAssignee")</h5>
-            <div class="overview-assignee">
-                @partial_dashboard_issuesbyassignee(project, openIssues)
-            </div>
+            @if(project.menuSetting.issue) {
+                <h5>@Messages("project.dashboard.openIssuesByAssignee")</h5>
+                <div class="overview-assignee">
+                    @partial_dashboard_issuesbyassignee(project, openIssues)
+                </div>
 
-            <hr>
+                <hr>
 
-            <h5>@Messages("project.dashboard.openIssuesByMilestone")</h5>
-            <div class="overview-milestone">
-                @partial_dashboard_issuesbymilestone(project, openIssues)
-            </div>
+                <h5>@Messages("project.dashboard.openIssuesByMilestone")</h5>
+                <div class="overview-milestone">
+                    @partial_dashboard_issuesbymilestone(project, openIssues)
+                </div>
+            }
 
-            @if(project.isGit){
-            <hr>
+            @if(project.menuSetting.pullRequest) {
+                @if(project.isGit){
+                    @if(project.menuSetting.issue) {
+                        <hr>
+                    }
 
-            <h5>@Messages("project.dashboard.pullRequests")</h5>
-            <div class="overview-pullrequest">
-                @partial_dashboard_pullrequests(project)
-            </div>
+                    <h5>@Messages("project.dashboard.pullRequests")</h5>
+                    <div class="overview-pullrequest">
+                        @partial_dashboard_pullrequests(project)
+                    </div>
+                }
             }
         </div>
 
-        <div class="span6">
-            <h5>@Messages("project.dashboard.openIssuesByLabel")</h5>
-            @partial_dashboard_issuesbylabel(project)
-        </div>
+        @if(project.menuSetting.issue) {
+            <div class="span6">
+                <h5>@Messages("project.dashboard.openIssuesByLabel")</h5>
+                @partial_dashboard_issuesbylabel(project)
+            </div>
+        }
     </div>
 </div>
 }
app/views/project/setting.scala.html
--- app/views/project/setting.scala.html
+++ app/views/project/setting.scala.html
@@ -123,6 +123,29 @@
                         <span class="note ml10">@Messages("project.defaultBranch.placeholder")</span>
                     </div>
                 </div>
+
+                <div class="box-wrap middle">
+                    <div class="cu-label vmiddle">@Messages("project.menu.setting")</div>
+                    <div class="cu-desc">
+                        <input type="checkbox" class="radio-btn" id="menuSettingCode" name="code" value="true" @if(project.menuSetting.code){checked="checked"}>
+                        <label for="menuSettingCode" class="bg-radiobtn label-public">@Messages("menu.code")</label>
+                        &nbsp;&nbsp;&nbsp;
+                        <input type="checkbox" class="radio-btn" id="menuSettingIssue" name="issue" value="true" @if(project.menuSetting.issue){checked="checked"}>
+                        <label for="menuSettingIssue" class="bg-radiobtn label-public">@Messages("menu.issue")</label>
+                        &nbsp;&nbsp;&nbsp;
+                        <input type="checkbox" class="radio-btn" id="menuSettingPullRequest" name="pullRequest" value="true" @if(project.menuSetting.pullRequest){checked="checked"}>
+                        <label for="menuSettingPullRequest" class="bg-radiobtn label-public">@Messages("menu.pullRequest")</label>
+                        &nbsp;&nbsp;&nbsp;
+                        <input type="checkbox" class="radio-btn" id="menuSettingReview" name="review" value="true" @if(project.menuSetting.review){checked="checked"}>
+                        <label for="menuSettingReview" class="bg-radiobtn label-public">@Messages("menu.review")</label>
+                        &nbsp;&nbsp;&nbsp;
+                        <input type="checkbox" class="radio-btn" id="menuSettingMilestone" name="milestone" value="true" @if(project.menuSetting.milestone){checked="checked"}>
+                        <label for="menuSettingMilestone" class="bg-radiobtn label-public">@Messages("milestone")</label>
+                        &nbsp;&nbsp;&nbsp;
+                        <input type="checkbox" class="radio-btn" id="menuSettingBoard" name="board" value="true" @if(project.menuSetting.board){checked="checked"}>
+                        <label for="menuSettingBoard" class="bg-radiobtn label-public">@Messages("menu.board")</label>
+                    </div>
+                </div>
             </div>
 
             <div class="box-wrap bottom">
app/views/projectMenu.scala.html
--- app/views/projectMenu.scala.html
+++ app/views/projectMenu.scala.html
@@ -44,44 +44,56 @@
                     @Messages("title.projectHome")
                 </a>
             </li>
-            <li class="@isActiveMenu(MenuType.CODE)">
-                <a href="@routes.CodeApp.codeBrowser(project.owner, project.name)">
-                    @Messages("menu.code")
-                </a>
-            </li>
-            <li class="@isActiveMenu(MenuType.ISSUE)">
-                <a href="@routes.IssueApp.issues(project.owner, project.name, "open")">
-                    @Messages("menu.issue")
-                    @if(Issue.countIssues(project.id, State.OPEN) > 0){
-                    <span class="project-menu-count">@Issue.countIssues(project.id, State.OPEN)</span>
-                    }
-                </a>
-            </li>
-            @if(project.vcs.equals("GIT")){
-                <li class="@isActiveMenu(MenuType.PULL_REQUEST)">
-                <a href="@getPullRequestURL(project)">
-                    @Messages("menu.pullRequest")
-                    @if(PullRequest.countOpenedPullRequests(project) > 0){
-                    <span class="project-menu-count">@PullRequest.countOpenedPullRequests(project)</span>
-                    }
-                </a>
-            </li>
+            @if(project.menuSetting.code) {
+                <li class="@isActiveMenu(MenuType.CODE)">
+                    <a href="@routes.CodeApp.codeBrowser(project.owner, project.name)">
+                        @Messages("menu.code")
+                    </a>
+                </li>
             }
-            <li class="@isActiveMenu(MenuType.PROJECT_REVIEW)">
-                <a href="@routes.ReviewThreadApp.reviewThreads(project.owner, project.name)">
-                @Messages("menu.review")
-                </a>
-            </li>
-            <li class="@isActiveMenu(MenuType.MILESTONE)">
-                <a href="@routes.MilestoneApp.milestones(project.owner, project.name)">
-                    @Messages("milestone")
-                </a>
-            </li>
-            <li class="@isActiveMenu(MenuType.BOARD)">
-                <a href="@routes.BoardApp.posts(project.owner, project.name)">
-                    @Messages("menu.board")
-                </a>
-            </li>
+            @if(project.menuSetting.issue) {
+                <li class="@isActiveMenu(MenuType.ISSUE)">
+                    <a href="@routes.IssueApp.issues(project.owner, project.name, "open")">
+                        @Messages("menu.issue")
+                        @if(Issue.countIssues(project.id, State.OPEN) > 0){
+                        <span class="project-menu-count">@Issue.countIssues(project.id, State.OPEN)</span>
+                        }
+                    </a>
+                </li>
+            }
+            @if(project.menuSetting.pullRequest) {
+                @if(project.vcs.equals("GIT")){
+                    <li class="@isActiveMenu(MenuType.PULL_REQUEST)">
+                    <a href="@getPullRequestURL(project)">
+                        @Messages("menu.pullRequest")
+                        @if(PullRequest.countOpenedPullRequests(project) > 0){
+                        <span class="project-menu-count">@PullRequest.countOpenedPullRequests(project)</span>
+                        }
+                    </a>
+                </li>
+                }
+            }
+            @if(project.menuSetting.review) {
+                <li class="@isActiveMenu(MenuType.PROJECT_REVIEW)">
+                    <a href="@routes.ReviewThreadApp.reviewThreads(project.owner, project.name)">
+                    @Messages("menu.review")
+                    </a>
+                </li>
+            }
+            @if(project.menuSetting.milestone) {
+                <li class="@isActiveMenu(MenuType.MILESTONE)">
+                    <a href="@routes.MilestoneApp.milestones(project.owner, project.name)">
+                        @Messages("milestone")
+                    </a>
+                </li>
+            }
+            @if(project.menuSetting.board) {
+                <li class="@isActiveMenu(MenuType.BOARD)">
+                    <a href="@routes.BoardApp.posts(project.owner, project.name)">
+                        @Messages("menu.board")
+                    </a>
+                </li>
+            }
         </ul>
         @if(AccessControl.isAllowed(UserApp.currentUser(), project.asResource(), Operation.UPDATE)){
         <div class="project-setting">
@@ -103,12 +115,20 @@
 <script type="text/javascript">
 $(document).ready(function(){
     var htKeyMap = {
-        "H": "@routes.ProjectApp.project(project.owner, project.name)",
-        "B": "@routes.BoardApp.posts(project.owner, project.name)",
-        "C": "@routes.CodeApp.codeBrowser(project.owner, project.name)",
-        "I": "@routes.IssueApp.issues(project.owner, project.name,"open")",
-        "M": "@routes.MilestoneApp.milestones(project.owner, project.name)"
-        @if(project.vcs.equals("GIT")){
+        "H": "@routes.ProjectApp.project(project.owner, project.name)"
+        @if(project.menuSetting.board) {
+            ,"B": "@routes.BoardApp.posts(project.owner, project.name)"
+        }
+        @if(project.menuSetting.code) {
+            ,"C": "@routes.CodeApp.codeBrowser(project.owner, project.name)"
+        }
+        @if(project.menuSetting.issue) {
+            ,"I": "@routes.IssueApp.issues(project.owner, project.name,"open")"
+        }
+        @if(project.menuSetting.milestone) {
+            ,"M": "@routes.MilestoneApp.milestones(project.owner, project.name)"
+        }
+        @if(project.menuSetting.pullRequest && project.vcs.equals("GIT")){
            ,"F": "@getPullRequestURL(project)"
         }
         @if(ProjectUser.roleOf(session.get("loginId"), project).equals("manager")){
app/views/user/partial_issues.scala.html
--- app/views/user/partial_issues.scala.html
+++ app/views/user/partial_issues.scala.html
@@ -83,7 +83,7 @@
             }
         </div>
         <div class="pull-right">
-            @if(issue.milestone != null) {
+            @if(project.menuSetting.milestone && issue.milestone != null) {
                 <div class="mileston-tag">
                     <a href="@routes.MilestoneApp.milestone(issue.project.owner, issue.project.name, issue.milestone.id)" data-toggle="tooltip" data-placement="top" title="@Messages("milestone")">
                     @issue.milestone.title
 
conf/evolutions/default/83.sql (added)
+++ conf/evolutions/default/83.sql
@@ -0,0 +1,28 @@
+# --- !Ups
+
+CREATE TABLE project_menu_setting (
+  id                        BIGINT NOT NULL,
+  project_id                BIGINT,
+  code                      BOOLEAN,
+  issue                     BOOLEAN,
+  pull_request              BOOLEAN,
+  review                    BOOLEAN,
+  milestone                 BOOLEAN,
+  board                     BOOLEAN,
+  CONSTRAINT pk_project_menu_setting PRIMARY KEY (id))
+;
+
+CREATE SEQUENCE project_menu_setting_seq;
+ALTER TABLE project_menu_setting ADD CONSTRAINT fk_project_menu_setting FOREIGN KEY (project_id) REFERENCES project (id) ON DELETE RESTRICT ON UPDATE RESTRICT;
+CREATE INDEX ix_project_menu_setting ON project_menu_setting (project_id);
+
+INSERT INTO project_menu_setting(id, project_id, code, issue, pull_request, review, milestone, board)
+SELECT nextval('project_menu_setting_seq'), id, 'TRUE', 'TRUE', 'TRUE', 'TRUE', 'TRUE', 'TRUE'
+FROM (SELECT id
+      FROM project);
+
+
+# --- !Downs
+
+DROP TABLE IF EXISTS project_menu_setting;
+DROP SEQUENCE IF EXISTS project_menu_setting_seq;
conf/messages
--- conf/messages
+++ conf/messages
@@ -541,6 +541,7 @@
 project.you.are.watching = You are watching {0} project.
 project.you.may.want.to.be.a.member = You can send a sign-up request for {0} project.
 project.you.want.to.be.a.member = You have sent a sign-up request for {0} project.
+project.menu.setting = Menu Setting
 pullRequest = Pull request
 pullRequest.accept = Accept
 pullRequest.additional.changes = Additional changes
conf/messages.ko
--- conf/messages.ko
+++ conf/messages.ko
@@ -541,6 +541,7 @@
 project.you.are.watching = {0} 프로젝트를 지켜보는 중입니다.
 project.you.may.want.to.be.a.member = {0} 프로젝트 멤버로 등록 요청을 할 수 있습니다.
 project.you.want.to.be.a.member = {0} 프로젝트 멤버로 등록 요청했습니다.
+project.menu.setting = 메뉴 설정
 pullRequest = 코드 보내기
 pullRequest.accept = 코드 받기
 pullRequest.additional.changes = 추가 변경 내역
Add a comment
List