@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
at recaptime-dev/main 215 lines 6.4 kB view raw
1<?php 2 3final class PhabricatorProjectSubprojectsController 4 extends PhabricatorProjectController { 5 6 public function shouldAllowPublic() { 7 return true; 8 } 9 10 public function handleRequest(AphrontRequest $request) { 11 $viewer = $request->getViewer(); 12 13 $response = $this->loadProject(); 14 if ($response) { 15 return $response; 16 } 17 18 $project = $this->getProject(); 19 $id = $project->getID(); 20 21 $can_edit = PhabricatorPolicyFilter::hasCapability( 22 $viewer, 23 $project, 24 PhabricatorPolicyCapability::CAN_EDIT); 25 26 $allows_subprojects = $project->supportsSubprojects(); 27 $allows_milestones = $project->supportsMilestones(); 28 29 $subproject_list = null; 30 $milestone_list = null; 31 32 if ($allows_subprojects) { 33 $subprojects = id(new PhabricatorProjectQuery()) 34 ->setViewer($viewer) 35 ->withParentProjectPHIDs(array($project->getPHID())) 36 ->needImages(true) 37 ->withIsMilestone(false) 38 ->execute(); 39 40 $subproject_list = id(new PHUIObjectBoxView()) 41 ->setHeaderText(pht('%s Subprojects', $project->getName())) 42 ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) 43 ->setObjectList( 44 id(new PhabricatorProjectListView()) 45 ->setViewer($viewer) 46 ->setProjects($subprojects) 47 ->setNoDataString(pht('This project has no subprojects.')) 48 ->renderList()); 49 } else { 50 $subprojects = array(); 51 } 52 53 if ($allows_milestones) { 54 $milestones = id(new PhabricatorProjectQuery()) 55 ->setViewer($viewer) 56 ->withParentProjectPHIDs(array($project->getPHID())) 57 ->needImages(true) 58 ->withIsMilestone(true) 59 ->setOrderVector(array('milestoneNumber', 'id')) 60 ->execute(); 61 62 $milestone_list = id(new PHUIObjectBoxView()) 63 ->setHeaderText(pht('%s Milestones', $project->getName())) 64 ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) 65 ->setObjectList( 66 id(new PhabricatorProjectListView()) 67 ->setViewer($viewer) 68 ->setProjects($milestones) 69 ->setNoDataString(pht('This project has no milestones.')) 70 ->renderList()); 71 } else { 72 $milestones = array(); 73 } 74 75 $curtain = $this->buildCurtainView( 76 $project, 77 $milestones, 78 $subprojects); 79 80 $nav = $this->newNavigation( 81 $project, 82 PhabricatorProject::ITEM_SUBPROJECTS); 83 84 $crumbs = $this->buildApplicationCrumbs(); 85 $crumbs->addTextCrumb(pht('Subprojects')); 86 $crumbs->setBorder(true); 87 88 $header = id(new PHUIHeaderView()) 89 ->setHeader(pht('Subprojects and Milestones')) 90 ->setHeaderIcon('fa-sitemap'); 91 92 require_celerity_resource('project-view-css'); 93 94 // This page isn't reachable via UI, but make it pretty anyways. 95 $info_view = null; 96 if (!$milestone_list && !$subproject_list) { 97 $info_view = id(new PHUIInfoView()) 98 ->setSeverity(PHUIInfoView::SEVERITY_NOTICE) 99 ->appendChild(pht('Milestone projects do not support subprojects '. 100 'or milestones.')); 101 } 102 103 $view = id(new PHUITwoColumnView()) 104 ->setHeader($header) 105 ->setCurtain($curtain) 106 ->addClass('project-view-home') 107 ->addClass('project-view-people-home') 108 ->setMainColumn(array( 109 $info_view, 110 $subproject_list, 111 $milestone_list, 112 )); 113 114 return $this->newPage() 115 ->setNavigation($nav) 116 ->setCrumbs($crumbs) 117 ->setTitle(array($project->getName(), pht('Subprojects'))) 118 ->appendChild($view); 119 } 120 121 private function buildCurtainView( 122 PhabricatorProject $project, 123 array $milestones, 124 array $subprojects) { 125 $viewer = $this->getViewer(); 126 $id = $project->getID(); 127 128 $can_create = $this->hasApplicationCapability( 129 ProjectCreateProjectsCapability::CAPABILITY); 130 131 $can_edit = PhabricatorPolicyFilter::hasCapability( 132 $viewer, 133 $project, 134 PhabricatorPolicyCapability::CAN_EDIT); 135 136 $allows_subprojects = $project->supportsSubprojects(); 137 $allows_milestones = $project->supportsMilestones(); 138 139 $curtain = $this->newCurtainView(); 140 141 $can_subproject = ($can_create && $can_edit && $allows_subprojects); 142 143 // If we're offering to create the first subproject, we're going to warn 144 // the user about the effects before moving forward. 145 if ($can_subproject && !$subprojects) { 146 $subproject_href = "/project/warning/{$id}/"; 147 $subproject_disabled = false; 148 $subproject_workflow = true; 149 } else { 150 $subproject_href = "/project/edit/?parent={$id}"; 151 $subproject_disabled = !$can_subproject; 152 $subproject_workflow = !$can_subproject; 153 } 154 155 $curtain->addAction( 156 id(new PhabricatorActionView()) 157 ->setName(pht('Create Subproject')) 158 ->setIcon('fa-plus') 159 ->setHref($subproject_href) 160 ->setDisabled($subproject_disabled) 161 ->setWorkflow($subproject_workflow)); 162 163 if ($allows_milestones && $milestones) { 164 $milestone_text = pht('Create Next Milestone'); 165 } else { 166 $milestone_text = pht('Create Milestone'); 167 } 168 169 $can_milestone = ($can_create && $can_edit && $allows_milestones); 170 $milestone_href = "/project/edit/?milestone={$id}"; 171 172 $curtain->addAction( 173 id(new PhabricatorActionView()) 174 ->setName($milestone_text) 175 ->setIcon('fa-plus') 176 ->setHref($milestone_href) 177 ->setDisabled(!$can_milestone) 178 ->setWorkflow(!$can_milestone)); 179 180 if (!$project->supportsSubprojects()) { 181 $note = pht( 182 'This project is a milestone, and milestones may not have '. 183 'subprojects.'); 184 } else { 185 if (!$subprojects) { 186 $note = pht('Subprojects can be created for this project.'); 187 } else { 188 $note = pht('This project has subprojects.'); 189 } 190 } 191 192 $curtain->newPanel() 193 ->setHeaderText(pht('Subprojects')) 194 ->appendChild($note); 195 196 if (!$project->supportsSubprojects()) { 197 $note = pht( 198 'This project is already a milestone, and milestones may not '. 199 'have their own milestones.'); 200 } else { 201 if (!$milestones) { 202 $note = pht('Milestones can be created for this project.'); 203 } else { 204 $note = pht('This project has milestones.'); 205 } 206 } 207 208 $curtain->newPanel() 209 ->setHeaderText(pht('Milestones')) 210 ->appendChild($note); 211 212 return $curtain; 213 } 214 215}