@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
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Split Repository EditEngine form into smaller pages

Summary:
Ref T10748. This allows an EditEngine form to be broken up into pages.

This is less powerful than `PHUIPagedFormView`, because the pages are not sequential / stateful. Each form saves immediately once it's submitted, and can not take you to a new form or back/forward in a series of forms.

For example, you can't create a workflow where the user fills out 5 pages of information before we create an object, like the current repository workflow does.

However, the only place we've ever wanted to do this is repositories and it's fairly bad there, so I feel reasonably confident we aren't going to miss this in the future.

(We do "choose a type of service/repository/rule -> fill out one page of info" fairly often, but can do this without the full-power paging stuff.)

Test Plan:
- Created a repository usin the new Manage UI, filling out only a handful of fields.
- Edited a repository using the new Manage UI.
- All forms are now EditEngine forms offering paged views of the big huge underlying form:

{F1254371}

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T10748

Differential Revision: https://secure.phabricator.com/D15832

+341 -19
+2
src/__phutil_library_map__.php
··· 2358 2358 'PhabricatorEditEngineSelectCommentAction' => 'applications/transactions/commentaction/PhabricatorEditEngineSelectCommentAction.php', 2359 2359 'PhabricatorEditEngineTokenizerCommentAction' => 'applications/transactions/commentaction/PhabricatorEditEngineTokenizerCommentAction.php', 2360 2360 'PhabricatorEditField' => 'applications/transactions/editfield/PhabricatorEditField.php', 2361 + 'PhabricatorEditPage' => 'applications/transactions/editengine/PhabricatorEditPage.php', 2361 2362 'PhabricatorEditType' => 'applications/transactions/edittype/PhabricatorEditType.php', 2362 2363 'PhabricatorEditor' => 'infrastructure/PhabricatorEditor.php', 2363 2364 'PhabricatorElasticFulltextStorageEngine' => 'applications/search/fulltextstorage/PhabricatorElasticFulltextStorageEngine.php', ··· 6872 6873 'PhabricatorEditEngineSelectCommentAction' => 'PhabricatorEditEngineCommentAction', 6873 6874 'PhabricatorEditEngineTokenizerCommentAction' => 'PhabricatorEditEngineCommentAction', 6874 6875 'PhabricatorEditField' => 'Phobject', 6876 + 'PhabricatorEditPage' => 'Phobject', 6875 6877 'PhabricatorEditType' => 'Phobject', 6876 6878 'PhabricatorEditor' => 'Phobject', 6877 6879 'PhabricatorElasticFulltextStorageEngine' => 'PhabricatorFulltextStorageEngine',
+3 -3
src/applications/base/PhabricatorApplication.php
··· 624 624 '(?P<id>[0-9]\d*)/)?'. 625 625 '(?:'. 626 626 '(?:'. 627 - '(?P<editAction>parameters|nodefault|nocreate|nomanage|comment)'. 627 + '(?P<editAction>parameters|nodefault|nocreate|nomanage|comment)/'. 628 628 '|'. 629 - '(?:form/(?P<formKey>[^/]+))'. 629 + '(?:form/(?P<formKey>[^/]+)/)?(?:page/(?P<pageKey>[^/]+)/)?'. 630 630 ')'. 631 - '/)?'; 631 + ')?'; 632 632 } 633 633 634 634 protected function getQueryRoutePattern($base = null) {
+21 -3
src/applications/diffusion/controller/DiffusionRepositoryEditDangerousController.php
··· 13 13 $drequest = $this->getDiffusionRequest(); 14 14 $repository = $drequest->getRepository(); 15 15 16 + $edit_uri = $this->getRepositoryControllerURI($repository, 'edit/'); 17 + 16 18 if (!$repository->canAllowDangerousChanges()) { 17 - return new Aphront400Response(); 19 + if ($repository->isSVN()) { 20 + return $this->newDialog() 21 + ->setTitle(pht('Not in Danger')) 22 + ->appendParagraph( 23 + pht( 24 + 'It is not possible for users to push any dangerous changes '. 25 + 'to a Subversion repository. Pushes to a Subversion repository '. 26 + 'can always be reverted and never destroy data.')) 27 + ->addCancelButton($edit_uri); 28 + } else { 29 + return $this->newDialog() 30 + ->setTitle(pht('Unprotectable Repository')) 31 + ->appendParagraph( 32 + pht( 33 + 'This repository can not be protected from dangerous changes '. 34 + 'because Phabricator does not control what users are allowed '. 35 + 'to push to it.')) 36 + ->addCancelButton($edit_uri); 37 + } 18 38 } 19 - 20 - $edit_uri = $this->getRepositoryControllerURI($repository, 'edit/'); 21 39 22 40 if ($request->isFormPost()) { 23 41 $xaction = id(new PhabricatorRepositoryTransaction())
+42
src/applications/diffusion/editor/DiffusionRepositoryEditEngine.php
··· 85 85 DiffusionCreateRepositoriesCapability::CAPABILITY); 86 86 } 87 87 88 + protected function newPages($object) { 89 + $panels = DiffusionRepositoryManagementPanel::getAllPanels(); 90 + 91 + $pages = array(); 92 + $uris = array(); 93 + foreach ($panels as $panel_key => $panel) { 94 + $panel->setRepository($object); 95 + 96 + $uris[$panel_key] = $panel->getPanelURI(); 97 + 98 + $page = $panel->newEditEnginePage(); 99 + if (!$page) { 100 + continue; 101 + } 102 + $pages[] = $page; 103 + } 104 + 105 + $basics_key = DiffusionRepositoryBasicsManagementPanel::PANELKEY; 106 + $basics_uri = $uris[$basics_key]; 107 + 108 + $more_pages = array( 109 + id(new PhabricatorEditPage()) 110 + ->setKey('encoding') 111 + ->setLabel(pht('Text Encoding')) 112 + ->setViewURI($basics_uri) 113 + ->setFieldKeys( 114 + array( 115 + 'encoding', 116 + )), 117 + id(new PhabricatorEditPage()) 118 + ->setKey('extensions') 119 + ->setLabel(pht('Extensions')) 120 + ->setIsDefault(true), 121 + ); 122 + 123 + foreach ($more_pages as $page) { 124 + $pages[] = $page; 125 + } 126 + 127 + return $pages; 128 + } 129 + 88 130 protected function buildCustomEditFields($object) { 89 131 $viewer = $this->getViewer(); 90 132
+8 -1
src/applications/diffusion/management/DiffusionRepositoryActionsManagementPanel.php
··· 13 13 return 1100; 14 14 } 15 15 16 + protected function getEditEngineFieldKeys() { 17 + return array( 18 + 'publish', 19 + 'autoclose', 20 + ); 21 + } 22 + 16 23 protected function buildManagementPanelActions() { 17 24 $repository = $this->getRepository(); 18 25 $viewer = $this->getViewer(); ··· 22 29 $repository, 23 30 PhabricatorPolicyCapability::CAN_EDIT); 24 31 25 - $actions_uri = $repository->getPathURI('edit/actions/'); 32 + $actions_uri = $this->getEditPageURI(); 26 33 27 34 return array( 28 35 id(new PhabricatorActionView())
+7 -1
src/applications/diffusion/management/DiffusionRepositoryAutomationManagementPanel.php
··· 13 13 return 800; 14 14 } 15 15 16 + protected function getEditEngineFieldKeys() { 17 + return array( 18 + 'automationBlueprintPHIDs', 19 + ); 20 + } 21 + 16 22 protected function buildManagementPanelActions() { 17 23 $repository = $this->getRepository(); 18 24 $viewer = $this->getViewer(); ··· 24 30 25 31 $can_test = $can_edit && $repository->canPerformAutomation(); 26 32 27 - $automation_uri = $repository->getPathURI('edit/automation/'); 33 + $automation_uri = $this->getEditPageURI(); 28 34 $test_uri = $repository->getPathURI('edit/testautomation/'); 29 35 30 36 return array(
+11 -2
src/applications/diffusion/management/DiffusionRepositoryBasicsManagementPanel.php
··· 13 13 return 100; 14 14 } 15 15 16 + protected function getEditEngineFieldKeys() { 17 + return array( 18 + 'name', 19 + 'callsign', 20 + 'shortName', 21 + 'description', 22 + ); 23 + } 24 + 16 25 protected function buildManagementPanelActions() { 17 26 $repository = $this->getRepository(); 18 27 $viewer = $this->getViewer(); ··· 22 31 $repository, 23 32 PhabricatorPolicyCapability::CAN_EDIT); 24 33 25 - $edit_uri = $repository->getPathURI('manage/'); 34 + $edit_uri = $this->getEditPageURI(); 26 35 $activate_uri = $repository->getPathURI('edit/activate/'); 27 36 $delete_uri = $repository->getPathURI('edit/delete/'); 28 - $encoding_uri = $repository->getPathURI('edit/encoding/'); 37 + $encoding_uri = $this->getEditPageURI('encoding'); 29 38 $dangerous_uri = $repository->getPathURI('edit/dangerous/'); 30 39 31 40 if ($repository->isTracked()) {
+9 -1
src/applications/diffusion/management/DiffusionRepositoryBranchesManagementPanel.php
··· 13 13 return 1000; 14 14 } 15 15 16 + protected function getEditEngineFieldKeys() { 17 + return array( 18 + 'defaultBranch', 19 + 'trackOnly', 20 + 'autocloseOnly', 21 + ); 22 + } 23 + 16 24 protected function buildManagementPanelActions() { 17 25 $repository = $this->getRepository(); 18 26 $viewer = $this->getViewer(); ··· 22 30 $repository, 23 31 PhabricatorPolicyCapability::CAN_EDIT); 24 32 25 - $branches_uri = $repository->getPathURI('edit/branches/'); 33 + $branches_uri = $this->getEditPageURI(); 26 34 27 35 return array( 28 36 id(new PhabricatorActionView())
+38
src/applications/diffusion/management/DiffusionRepositoryManagementPanel.php
··· 98 98 return $this->controller->newTimeline($this->getRepository()); 99 99 } 100 100 101 + final public function getPanelURI() { 102 + $repository = $this->getRepository(); 103 + $key = $this->getManagementPanelKey(); 104 + return $repository->getPathURI("manage/{$key}/"); 105 + } 106 + 107 + final public function newEditEnginePage() { 108 + $field_keys = $this->getEditEngineFieldKeys(); 109 + if (!$field_keys) { 110 + return null; 111 + } 112 + 113 + $key = $this->getManagementPanelKey(); 114 + $label = $this->getManagementPanelLabel(); 115 + $panel_uri = $this->getPanelURI(); 116 + 117 + return id(new PhabricatorEditPage()) 118 + ->setKey($key) 119 + ->setLabel($label) 120 + ->setViewURI($panel_uri) 121 + ->setFieldKeys($field_keys); 122 + } 123 + 124 + protected function getEditEngineFieldKeys() { 125 + return array(); 126 + } 127 + 128 + protected function getEditPageURI($page = null) { 129 + if ($page === null) { 130 + $page = $this->getManagementPanelKey(); 131 + } 132 + 133 + $repository = $this->getRepository(); 134 + $id = $repository->getID(); 135 + return "/diffusion/editpro/{$id}/page/{$page}/"; 136 + } 137 + 138 + 101 139 }
+9 -1
src/applications/diffusion/management/DiffusionRepositoryPoliciesManagementPanel.php
··· 13 13 return 300; 14 14 } 15 15 16 + protected function getEditEngineFieldKeys() { 17 + return array( 18 + 'policy.view', 19 + 'policy.edit', 20 + 'policy.push', 21 + ); 22 + } 23 + 16 24 protected function buildManagementPanelActions() { 17 25 $repository = $this->getRepository(); 18 26 $viewer = $this->getViewer(); ··· 22 30 $repository, 23 31 PhabricatorPolicyCapability::CAN_EDIT); 24 32 25 - $edit_uri = $repository->getPathURI('manage/'); 33 + $edit_uri = $this->getEditPageURI(); 26 34 27 35 return array( 28 36 id(new PhabricatorActionView())
+7 -1
src/applications/diffusion/management/DiffusionRepositoryStagingManagementPanel.php
··· 13 13 return 700; 14 14 } 15 15 16 + protected function getEditEngineFieldKeys() { 17 + return array( 18 + 'stagingAreaURI', 19 + ); 20 + } 21 + 16 22 protected function buildManagementPanelActions() { 17 23 $repository = $this->getRepository(); 18 24 $viewer = $this->getViewer(); ··· 22 28 $repository, 23 29 PhabricatorPolicyCapability::CAN_EDIT); 24 30 25 - $staging_uri = $repository->getPathURI('edit/staging/'); 31 + $staging_uri = $this->getEditPageURI(); 26 32 27 33 return array( 28 34 id(new PhabricatorActionView())
+8 -1
src/applications/diffusion/management/DiffusionRepositorySymbolsManagementPanel.php
··· 13 13 return 900; 14 14 } 15 15 16 + protected function getEditEngineFieldKeys() { 17 + return array( 18 + 'symbolLanguages', 19 + 'symbolRepositoryPHIDs', 20 + ); 21 + } 22 + 16 23 protected function buildManagementPanelActions() { 17 24 $repository = $this->getRepository(); 18 25 $viewer = $this->getViewer(); ··· 22 29 $repository, 23 30 PhabricatorPolicyCapability::CAN_EDIT); 24 31 25 - $symbols_uri = $repository->getPathURI('edit/symbols/'); 32 + $symbols_uri = $this->getEditPageURI(); 26 33 27 34 return array( 28 35 id(new PhabricatorActionView())
+118 -5
src/applications/transactions/editengine/PhabricatorEditEngine.php
··· 24 24 private $editEngineConfiguration; 25 25 private $contextParameters = array(); 26 26 private $targetObject; 27 + private $page; 28 + private $pages; 27 29 28 30 final public function setViewer(PhabricatorUser $viewer) { 29 31 $this->viewer = $viewer; ··· 145 147 $config = $this->getEditEngineConfiguration(); 146 148 $fields = $this->willConfigureFields($object, $fields); 147 149 $fields = $config->applyConfigurationToFields($this, $object, $fields); 150 + 151 + $fields = $this->applyPageToFields($object, $fields); 148 152 149 153 return $fields; 150 154 } ··· 492 496 return implode('', $parts); 493 497 } 494 498 499 + public function getEffectiveObjectViewURI($object) { 500 + $page = $this->getSelectedPage(); 501 + if ($page) { 502 + $view_uri = $page->getViewURI(); 503 + if ($view_uri !== null) { 504 + return $view_uri; 505 + } 506 + } 507 + 508 + return $this->getObjectViewURI($object); 509 + } 510 + 511 + public function getEffectiveObjectEditCancelURI($object) { 512 + $page = $this->getSelectedPage(); 513 + if ($page) { 514 + $view_uri = $page->getViewURI(); 515 + if ($view_uri !== null) { 516 + return $view_uri; 517 + } 518 + } 519 + 520 + return $this->getObjectEditCancelURI($object); 521 + } 522 + 495 523 496 524 /* -( Creating and Loading Objects )--------------------------------------- */ 497 525 ··· 810 838 return $this->buildDisabledFormResponse($object, $config); 811 839 } 812 840 841 + $page_key = $request->getURIData('pageKey'); 842 + if (strlen($page_key)) { 843 + $page = $this->selectPage($object, $page_key); 844 + if (!$page) { 845 + return new Aphront404Response(); 846 + } 847 + } 848 + 813 849 switch ($action) { 814 850 case 'parameters': 815 851 return $this->buildParametersResponse($object); ··· 841 877 } else { 842 878 $crumbs->addTextCrumb( 843 879 $this->getObjectEditShortText($object), 844 - $this->getObjectViewURI($object)); 880 + $this->getEffectiveObjectViewURI($object)); 845 881 846 882 $edit_text = pht('Edit'); 847 883 if ($final) { ··· 1029 1065 $cancel_uri = $this->getObjectCreateCancelURI($object); 1030 1066 $submit_button = $this->getObjectCreateButtonText($object); 1031 1067 } else { 1032 - $cancel_uri = $this->getObjectEditCancelURI($object); 1068 + $cancel_uri = $this->getEffectiveObjectEditCancelURI($object); 1033 1069 $submit_button = $this->getObjectEditButtonText($object); 1034 1070 } 1035 1071 ··· 1079 1115 $object, 1080 1116 array $xactions) { 1081 1117 return id(new AphrontRedirectResponse()) 1082 - ->setURI($this->getObjectViewURI($object)); 1118 + ->setURI($this->getEffectiveObjectViewURI($object)); 1083 1119 } 1084 1120 1085 1121 private function buildEditForm($object, array $fields) { ··· 1103 1139 $cancel_uri = $this->getObjectCreateCancelURI($object); 1104 1140 $submit_button = $this->getObjectCreateButtonText($object); 1105 1141 } else { 1106 - $cancel_uri = $this->getObjectEditCancelURI($object); 1142 + $cancel_uri = $this->getEffectiveObjectEditCancelURI($object); 1107 1143 $submit_button = $this->getObjectEditButtonText($object); 1108 1144 } 1109 1145 ··· 1547 1583 $fields = $this->buildEditFields($object); 1548 1584 1549 1585 $is_preview = $request->isPreviewRequest(); 1550 - $view_uri = $this->getObjectViewURI($object); 1586 + $view_uri = $this->getEffectiveObjectViewURI($object); 1551 1587 1552 1588 $template = $object->getApplicationTransactionTemplate(); 1553 1589 $comment_template = $template->getApplicationTransactionCommentObject(); ··· 1953 1989 $this->getViewer(), 1954 1990 $this, 1955 1991 PhabricatorPolicyCapability::CAN_EDIT); 1992 + } 1993 + 1994 + /* -( Form Pages )--------------------------------------------------------- */ 1995 + 1996 + 1997 + public function getSelectedPage() { 1998 + return $this->page; 1999 + } 2000 + 2001 + 2002 + private function selectPage($object, $page_key) { 2003 + $pages = $this->getPages($object); 2004 + 2005 + if (empty($pages[$page_key])) { 2006 + return null; 2007 + } 2008 + 2009 + $this->page = $pages[$page_key]; 2010 + return $this->page; 2011 + } 2012 + 2013 + 2014 + protected function newPages($object) { 2015 + return array(); 2016 + } 2017 + 2018 + 2019 + protected function getPages($object) { 2020 + if ($this->pages === null) { 2021 + $pages = $this->newPages($object); 2022 + 2023 + assert_instances_of($pages, 'PhabricatorEditPage'); 2024 + $pages = mpull($pages, null, 'getKey'); 2025 + 2026 + $this->pages = $pages; 2027 + } 2028 + 2029 + return $this->pages; 2030 + } 2031 + 2032 + private function applyPageToFields($object, array $fields) { 2033 + $pages = $this->getPages($object); 2034 + if (!$pages) { 2035 + return $fields; 2036 + } 2037 + 2038 + $page_picks = array(); 2039 + $default_key = head($pages)->getKey(); 2040 + foreach ($pages as $page_key => $page) { 2041 + foreach ($page->getFieldKeys() as $field_key) { 2042 + $page_picks[$field_key] = $page_key; 2043 + } 2044 + if ($page->getIsDefault()) { 2045 + $default_key = $page_key; 2046 + } 2047 + } 2048 + 2049 + $page_map = array_fill_keys(array_keys($pages), array()); 2050 + foreach ($fields as $field_key => $field) { 2051 + if (isset($page_picks[$field_key])) { 2052 + $page_map[$page_picks[$field_key]][$field_key] = $field; 2053 + continue; 2054 + } 2055 + 2056 + // TODO: Maybe let the field pick a page to associate itself with so 2057 + // extensions can force themselves onto a particular page? 2058 + 2059 + $page_map[$default_key][$field_key] = $field; 2060 + } 2061 + 2062 + $page = $this->getSelectedPage(); 2063 + if (!$page) { 2064 + $page = head($pages); 2065 + } 2066 + 2067 + $selected_key = $page->getKey(); 2068 + return $page_map[$selected_key]; 1956 2069 } 1957 2070 1958 2071
+58
src/applications/transactions/editengine/PhabricatorEditPage.php
··· 1 + <?php 2 + 3 + 4 + final class PhabricatorEditPage 5 + extends Phobject { 6 + 7 + private $key; 8 + private $label; 9 + private $fieldKeys = array(); 10 + private $viewURI; 11 + private $isDefault; 12 + 13 + public function setKey($key) { 14 + $this->key = $key; 15 + return $this; 16 + } 17 + 18 + public function getKey() { 19 + return $this->key; 20 + } 21 + 22 + public function setLabel($label) { 23 + $this->label = $label; 24 + return $this; 25 + } 26 + 27 + public function getLabel() { 28 + return $this->label; 29 + } 30 + 31 + public function setFieldKeys(array $field_keys) { 32 + $this->fieldKeys = $field_keys; 33 + return $this; 34 + } 35 + 36 + public function getFieldKeys() { 37 + return $this->fieldKeys; 38 + } 39 + 40 + public function setIsDefault($is_default) { 41 + $this->isDefault = $is_default; 42 + return $this; 43 + } 44 + 45 + public function getIsDefault() { 46 + return $this->isDefault; 47 + } 48 + 49 + public function setViewURI($view_uri) { 50 + $this->viewURI = $view_uri; 51 + return $this; 52 + } 53 + 54 + public function getViewURI() { 55 + return $this->viewURI; 56 + } 57 + 58 + }