@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.

Provide contextual documentation explaining how to prefill ApplicationEditor create forms

Summary:
Ref T9132. Although forms do generally support prefilling right now, you have to guess how to do it.

Provide an explicit action showing you which values are supported and how to prefill them. This is generated automatically when an application switches to ApplicationEditor.

Test Plan:
{F939804}

{F939805}

{F939806}

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T9132

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

+545 -18
+3 -3
resources/celerity/map.php
··· 7 7 */ 8 8 return array( 9 9 'names' => array( 10 - 'core.pkg.css' => 'dd913c69', 10 + 'core.pkg.css' => 'bbeb85d2', 11 11 'core.pkg.js' => '47dc9ebb', 12 12 'darkconsole.pkg.js' => 'e7393ebb', 13 13 'differential.pkg.css' => '2de124c9', ··· 25 25 'rsrc/css/aphront/notification.css' => '9c279160', 26 26 'rsrc/css/aphront/panel-view.css' => '8427b78d', 27 27 'rsrc/css/aphront/phabricator-nav-view.css' => 'a24cb589', 28 - 'rsrc/css/aphront/table-view.css' => '61543e7a', 28 + 'rsrc/css/aphront/table-view.css' => '6d01d468', 29 29 'rsrc/css/aphront/tokenizer.css' => '04875312', 30 30 'rsrc/css/aphront/tooltip.css' => '7672b60f', 31 31 'rsrc/css/aphront/typeahead-browse.css' => 'd8581d2c', ··· 498 498 'aphront-list-filter-view-css' => '5d6f0526', 499 499 'aphront-multi-column-view-css' => 'fd18389d', 500 500 'aphront-panel-view-css' => '8427b78d', 501 - 'aphront-table-view-css' => '61543e7a', 501 + 'aphront-table-view-css' => '6d01d468', 502 502 'aphront-tokenizer-control-css' => '04875312', 503 503 'aphront-tooltip-css' => '7672b60f', 504 504 'aphront-typeahead-control-css' => '0e403212',
+2
src/__phutil_library_map__.php
··· 1571 1571 'PhabricatorApplicationDetailViewController' => 'applications/meta/controller/PhabricatorApplicationDetailViewController.php', 1572 1572 'PhabricatorApplicationEditController' => 'applications/meta/controller/PhabricatorApplicationEditController.php', 1573 1573 'PhabricatorApplicationEditEngine' => 'applications/transactions/editengine/PhabricatorApplicationEditEngine.php', 1574 + 'PhabricatorApplicationEditHTTPParameterHelpView' => 'applications/transactions/view/PhabricatorApplicationEditHTTPParameterHelpView.php', 1574 1575 'PhabricatorApplicationEmailCommandsController' => 'applications/meta/controller/PhabricatorApplicationEmailCommandsController.php', 1575 1576 'PhabricatorApplicationLaunchView' => 'applications/meta/view/PhabricatorApplicationLaunchView.php', 1576 1577 'PhabricatorApplicationPanelController' => 'applications/meta/controller/PhabricatorApplicationPanelController.php', ··· 5500 5501 'PhabricatorApplicationDetailViewController' => 'PhabricatorApplicationsController', 5501 5502 'PhabricatorApplicationEditController' => 'PhabricatorApplicationsController', 5502 5503 'PhabricatorApplicationEditEngine' => 'Phobject', 5504 + 'PhabricatorApplicationEditHTTPParameterHelpView' => 'AphrontView', 5503 5505 'PhabricatorApplicationEmailCommandsController' => 'PhabricatorApplicationsController', 5504 5506 'PhabricatorApplicationLaunchView' => 'AphrontTagView', 5505 5507 'PhabricatorApplicationPanelController' => 'PhabricatorApplicationsController',
+4
src/applications/base/PhabricatorApplication.php
··· 635 635 return array(); 636 636 } 637 637 638 + protected function getEditRoutePattern($base) { 639 + return $base.'(?:(?P<id>[0-9]\d*)/)?(?:(?P<editAction>parameters)/)?'; 640 + } 641 + 638 642 }
+1 -1
src/applications/paste/application/PhabricatorPasteApplication.php
··· 39 39 '/paste/' => array( 40 40 '(query/(?P<queryKey>[^/]+)/)?' => 'PhabricatorPasteListController', 41 41 'create/' => 'PhabricatorPasteEditController', 42 - 'edit/(?P<id>[1-9]\d*)/' => 'PhabricatorPasteEditController', 42 + $this->getEditRoutePattern('edit/') => 'PhabricatorPasteEditController', 43 43 'raw/(?P<id>[1-9]\d*)/' => 'PhabricatorPasteRawController', 44 44 'comment/(?P<id>[1-9]\d*)/' => 'PhabricatorPasteCommentController', 45 45 ),
+1 -1
src/applications/paste/controller/PhabricatorPasteListController.php
··· 18 18 $crumbs->addAction( 19 19 id(new PHUIListItemView()) 20 20 ->setName(pht('Create Paste')) 21 - ->setHref($this->getApplicationURI('create/')) 21 + ->setHref($this->getApplicationURI('edit/')) 22 22 ->setIcon('fa-plus-square')); 23 23 24 24 return $crumbs;
+8
src/applications/paste/editor/PhabricatorPasteEditEngine.php
··· 41 41 id(new PhabricatorTextEditField()) 42 42 ->setKey('title') 43 43 ->setLabel(pht('Title')) 44 + ->setDescription(pht('Name of the paste.')) 44 45 ->setTransactionType(PhabricatorPasteTransaction::TYPE_TITLE) 45 46 ->setValue($object->getTitle()), 46 47 id(new PhabricatorSelectEditField()) 47 48 ->setKey('language') 48 49 ->setLabel(pht('Language')) 50 + ->setDescription( 51 + pht( 52 + 'Programming language to interpret the paste as for syntax '. 53 + 'highlighting. By default, the language is inferred from the '. 54 + 'title.')) 49 55 ->setAliases(array('lang')) 50 56 ->setTransactionType(PhabricatorPasteTransaction::TYPE_LANGUAGE) 51 57 ->setValue($object->getLanguage()) ··· 53 59 id(new PhabricatorSelectEditField()) 54 60 ->setKey('status') 55 61 ->setLabel(pht('Status')) 62 + ->setDescription(pht('Archive the paste.')) 56 63 ->setTransactionType(PhabricatorPasteTransaction::TYPE_STATUS) 57 64 ->setValue($object->getStatus()) 58 65 ->setOptions(PhabricatorPaste::getStatusNameMap()), 59 66 id(new PhabricatorTextAreaEditField()) 60 67 ->setKey('text') 61 68 ->setLabel(pht('Text')) 69 + ->setDescription(pht('The main body text of the paste.')) 62 70 ->setTransactionType(PhabricatorPasteTransaction::TYPE_CONTENT) 63 71 ->setMonospaced(true) 64 72 ->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_TALL)
+156 -13
src/applications/transactions/editengine/PhabricatorApplicationEditEngine.php
··· 4 4 5 5 private $viewer; 6 6 private $controller; 7 + private $isCreate; 7 8 8 9 final public function setViewer(PhabricatorUser $viewer) { 9 10 $this->viewer = $viewer; ··· 44 45 'key' => 'policy.view', 45 46 'aliases' => array('view'), 46 47 'capability' => PhabricatorPolicyCapability::CAN_VIEW, 48 + 'label' => pht('View Policy'), 49 + 'description' => pht('Controls who can view the object.'), 47 50 ), 48 51 PhabricatorTransactions::TYPE_EDIT_POLICY => array( 49 52 'key' => 'policy.edit', 50 53 'aliases' => array('edit'), 51 54 'capability' => PhabricatorPolicyCapability::CAN_EDIT, 55 + 'label' => pht('Edit Policy'), 56 + 'description' => pht('Controls who can edit the object.'), 52 57 ), 53 58 PhabricatorTransactions::TYPE_JOIN_POLICY => array( 54 59 'key' => 'policy.join', 55 60 'aliases' => array('join'), 56 61 'capability' => PhabricatorPolicyCapability::CAN_JOIN, 62 + 'label' => pht('Join Policy'), 63 + 'description' => pht('Controls who can join the object.'), 57 64 ), 58 65 ); 59 66 ··· 65 72 $capability = $spec['capability']; 66 73 $key = $spec['key']; 67 74 $aliases = $spec['aliases']; 75 + $label = $spec['label']; 76 + $description = $spec['description']; 68 77 69 78 $policy_field = id(new PhabricatorPolicyEditField()) 70 79 ->setKey($key) 80 + ->setLabel($label) 81 + ->setDescription($description) 71 82 ->setAliases($aliases) 72 83 ->setCapability($capability) 73 84 ->setPolicies($policies) ··· 81 92 if (isset($types[$type_space])) { 82 93 $space_field = id(new PhabricatorSpaceEditField()) 83 94 ->setKey('spacePHID') 95 + ->setLabel(pht('Space')) 96 + ->setDescription( 97 + pht('Shifts the object in the Spaces application.')) 84 98 ->setAliases(array('space', 'policy.space')) 85 99 ->setTransactionType($type_space) 86 100 ->setValue($object->getSpacePHID()); ··· 112 126 $edge_field = id(new PhabricatorDatasourceEditField()) 113 127 ->setKey('projectPHIDs') 114 128 ->setLabel(pht('Projects')) 129 + ->setDescription( 130 + pht( 131 + 'Add or remove associated projects.')) 115 132 ->setDatasource(new PhabricatorProjectDatasource()) 116 133 ->setAliases(array('project', 'projects')) 117 134 ->setTransactionType($edge_type) ··· 137 154 $subscribers_field = id(new PhabricatorDatasourceEditField()) 138 155 ->setKey('subscriberPHIDs') 139 156 ->setLabel(pht('Subscribers')) 157 + ->setDescription(pht('Manage subscribers.')) 140 158 ->setDatasource(new PhabricatorMetaMTAMailableDatasource()) 141 159 ->setAliases(array('subscriber', 'subscribers')) 142 160 ->setTransactionType($subscribers_type) ··· 157 175 abstract protected function getObjectCreateShortText($object); 158 176 abstract protected function getObjectEditShortText($object); 159 177 abstract protected function getObjectViewURI($object); 178 + 179 + protected function getObjectEditURI($object) { 180 + return $this->getController()->getApplicationURI('edit/'); 181 + } 160 182 161 183 protected function getObjectCreateCancelURI($object) { 162 184 return $this->getController()->getApplicationURI(); ··· 174 196 return pht('Save Changes'); 175 197 } 176 198 199 + protected function getEditURI($object, $path = null) { 200 + $parts = array( 201 + $this->getObjectEditURI($object), 202 + ); 203 + 204 + if (!$this->getIsCreate()) { 205 + $parts[] = $object->getID().'/'; 206 + } 207 + 208 + if ($path !== null) { 209 + $parts[] = $path; 210 + } 211 + 212 + return implode('', $parts); 213 + } 214 + 215 + final protected function setIsCreate($is_create) { 216 + $this->isCreate = $is_create; 217 + return $this; 218 + } 219 + 220 + final protected function getIsCreate() { 221 + return $this->isCreate; 222 + } 223 + 177 224 final public function buildResponse() { 178 225 $controller = $this->getController(); 179 226 $viewer = $this->getViewer(); ··· 194 241 return new Aphront404Response(); 195 242 } 196 243 197 - $is_create = false; 244 + $this->setIsCreate(false); 198 245 } else { 199 246 $object = $this->newEditableObject(); 200 247 201 - $is_create = true; 248 + $this->setIsCreate(true); 202 249 } 203 250 204 251 $fields = $this->buildEditFields($object); ··· 209 256 ->setObject($object); 210 257 } 211 258 259 + $action = $request->getURIData('editAction'); 260 + switch ($action) { 261 + case 'parameters': 262 + return $this->buildParametersResponse($object, $fields); 263 + } 264 + 212 265 $validation_exception = null; 213 266 if ($request->isFormPost()) { 214 267 foreach ($fields as $field) { ··· 238 291 $validation_exception = $ex; 239 292 } 240 293 } else { 241 - if ($is_create) { 294 + if ($this->getIsCreate()) { 242 295 foreach ($fields as $field) { 243 296 $field->readValueFromRequest($request); 244 297 } ··· 252 305 $box = id(new PHUIObjectBoxView()) 253 306 ->setUser($viewer); 254 307 255 - $crumbs = $controller->buildApplicationCrumbsForEditEngine(); 308 + $crumbs = $this->buildCrumbs($object, $final = true); 256 309 257 - if ($is_create) { 310 + if ($this->getIsCreate()) { 258 311 $header_text = $this->getObjectCreateTitleText($object); 259 312 260 - $crumbs->addTextCrumb( 261 - $this->getObjectCreateShortText($object)); 262 - 263 313 $cancel_uri = $this->getObjectCreateCancelURI($object); 264 314 $submit_button = $this->getObjectCreateButtonText($object); 265 315 } else { 266 316 $header_text = $this->getObjectEditTitleText($object); 267 317 268 - $crumbs->addTextCrumb( 269 - $this->getObjectEditShortText($object), 270 - $this->getObjectViewURI($object)); 271 - 272 318 $cancel_uri = $this->getObjectEditCancelURI($object); 273 319 $submit_button = $this->getObjectEditButtonText($object); 274 320 } 275 321 276 - $box->setHeaderText($header_text); 322 + $header = id(new PHUIHeaderView()) 323 + ->setHeader($header_text); 324 + 325 + $action_button = $this->buildEditFormActionButton($object); 326 + 327 + $header->addActionLink($action_button); 328 + 329 + $box->setHeader($header); 277 330 278 331 $form = id(new AphrontFormView()) 279 332 ->setUser($viewer); ··· 299 352 ->appendChild($box); 300 353 } 301 354 355 + private function buildParametersResponse($object, array $fields) { 356 + $controller = $this->getController(); 357 + $viewer = $this->getViewer(); 358 + $request = $controller->getRequest(); 359 + 360 + $crumbs = $this->buildCrumbs($object); 361 + $crumbs->addTextCrumb(pht('HTTP Parameters')); 362 + 363 + $header = id(new PHUIHeaderView()) 364 + ->setHeader( 365 + pht( 366 + 'HTTP Parameters: %s', 367 + $this->getObjectCreateShortText($object))); 368 + 369 + // TODO: Upgrade to DocumentViewPro. 370 + 371 + $document = id(new PHUIDocumentView()) 372 + ->setUser($viewer) 373 + ->setHeader($header); 374 + 375 + $document->appendChild( 376 + id(new PhabricatorApplicationEditHTTPParameterHelpView()) 377 + ->setUser($viewer) 378 + ->setFields($fields)); 379 + 380 + return $controller->newPage() 381 + ->setTitle(pht('HTTP Parameters')) 382 + ->setCrumbs($crumbs) 383 + ->appendChild($document); 384 + } 385 + 386 + private function buildCrumbs($object, $final = false) { 387 + $controller = $this->getcontroller(); 388 + 389 + $crumbs = $controller->buildApplicationCrumbsForEditEngine(); 390 + if ($this->getIsCreate()) { 391 + $create_text = $this->getObjectCreateShortText($object); 392 + if ($final) { 393 + $crumbs->addTextCrumb($create_text); 394 + } else { 395 + $edit_uri = $this->getEditURI($object); 396 + $crumbs->addTextCrumb($create_text, $edit_uri); 397 + } 398 + } else { 399 + $crumbs->addTextCrumb( 400 + $this->getObjectEditShortText($object), 401 + $this->getObjectViewURI($object)); 402 + 403 + $edit_text = pht('Edit'); 404 + if ($final) { 405 + $crumbs->addTextCrumb($edit_text); 406 + } else { 407 + $edit_uri = $this->getEditURI($object); 408 + $crumbs->addTextCrumb($edit_text, $edit_uri); 409 + } 410 + } 411 + 412 + return $crumbs; 413 + } 414 + 415 + private function buildEditFormActionButton($object) { 416 + $viewer = $this->getViewer(); 417 + 418 + $action_view = id(new PhabricatorActionListView()) 419 + ->setUser($viewer); 420 + 421 + foreach ($this->buildEditFormActions($object) as $action) { 422 + $action_view->addAction($action); 423 + } 424 + 425 + $action_button = id(new PHUIButtonView()) 426 + ->setTag('a') 427 + ->setText(pht('Actions')) 428 + ->setHref('#') 429 + ->setIconFont('fa-bars') 430 + ->setDropdownMenu($action_view); 431 + 432 + return $action_button; 433 + } 434 + 435 + private function buildEditFormActions($object) { 436 + $actions = array(); 437 + 438 + $actions[] = id(new PhabricatorActionView()) 439 + ->setName(pht('Show HTTP Parameters')) 440 + ->setIcon('fa-crosshairs') 441 + ->setHref($this->getEditURI($object, 'parameters/')); 442 + 443 + return $actions; 444 + } 302 445 303 446 }
+14
src/applications/transactions/editfield/PhabricatorEditField.php
··· 11 11 private $object; 12 12 private $transactionType; 13 13 private $metadata = array(); 14 + private $description; 14 15 15 16 public function setKey($key) { 16 17 $this->key = $key; ··· 55 56 56 57 public function getObject() { 57 58 return $this->object; 59 + } 60 + 61 + public function setDescription($description) { 62 + $this->description = $description; 63 + return $this; 64 + } 65 + 66 + public function getDescription() { 67 + return $this->description; 58 68 } 59 69 60 70 abstract protected function newControl(); ··· 207 217 } 208 218 209 219 return $list; 220 + } 221 + 222 + public function getHTTPParameterType() { 223 + return 'string'; 210 224 } 211 225 212 226 }
+4
src/applications/transactions/editfield/PhabricatorPolicyEditField.php
··· 51 51 return $control; 52 52 } 53 53 54 + public function getHTTPParameterType() { 55 + return 'phid'; 56 + } 57 + 54 58 }
+4
src/applications/transactions/editfield/PhabricatorSelectEditField.php
··· 22 22 ->setOptions($this->getOptions()); 23 23 } 24 24 25 + public function getHTTPParameterType() { 26 + return 'select'; 27 + } 28 + 25 29 }
+4
src/applications/transactions/editfield/PhabricatorSpaceEditField.php
··· 9 9 return null; 10 10 } 11 11 12 + public function getHTTPParameterType() { 13 + return 'phid'; 14 + } 15 + 12 16 }
+4
src/applications/transactions/editfield/PhabricatorTokenizerEditField.php
··· 87 87 return $new; 88 88 } 89 89 90 + public function getHTTPParameterType() { 91 + return 'list<phid>'; 92 + } 93 + 90 94 }
+336
src/applications/transactions/view/PhabricatorApplicationEditHTTPParameterHelpView.php
··· 1 + <?php 2 + 3 + /** 4 + * Renders the "HTTP Parameters" help page for edit engines. 5 + * 6 + * This page has a ton of text and specialized rendering on it, this class 7 + * just pulls it out of the main @{class:PhabricatorApplicationEditEngine}. 8 + */ 9 + final class PhabricatorApplicationEditHTTPParameterHelpView 10 + extends AphrontView { 11 + 12 + private $object; 13 + private $fields; 14 + 15 + public function setObject($object) { 16 + $this->object = $object; 17 + return $this; 18 + } 19 + 20 + public function getObject() { 21 + return $this->object; 22 + } 23 + 24 + public function setFields(array $fields) { 25 + $this->fields = $fields; 26 + return $this; 27 + } 28 + 29 + public function getFields() { 30 + return $this->fields; 31 + } 32 + 33 + public function render() { 34 + $object = $this->getObject(); 35 + $fields = $this->getFields(); 36 + 37 + $uri = 'https://your.install.com/application/edit/'; 38 + 39 + // Remove fields which do not expose an HTTP parameter type. 40 + $types = array(); 41 + foreach ($fields as $key => $field) { 42 + $type = $field->getHTTPParameterType(); 43 + if ($type === null) { 44 + unset($fields[$key]); 45 + } 46 + $types[$type][] = $field; 47 + } 48 + 49 + $intro = pht(<<<EOTEXT 50 + When creating objects in the web interface, you can use HTTP parameters to 51 + prefill fields in the form. This allows you to quickly create a link to a 52 + form with some of the fields already filled in with default values. 53 + 54 + To prefill a form, start by finding the URI for the form you want to prefill. 55 + Do this by navigating to the relevant application, clicking the "Create" button 56 + for the type of object you want to create, and then copying the URI out of your 57 + browser's address bar. It will usually look something like this: 58 + 59 + ``` 60 + %s 61 + ``` 62 + 63 + However, `your.install.com` will be the domain where your copy of Phabricator 64 + is installed, and `application/` will be the URI for an application. Some 65 + applications have multiple forms for creating objects or URIs that look a little 66 + different than this example, so the URI may not look exactly like this. 67 + 68 + To prefill the form, add properly encoded HTTP parameters to the URI. You 69 + should end up with something like this: 70 + 71 + ``` 72 + %s?title=Platyplus&body=Ornithopter 73 + ``` 74 + 75 + If the form has `title` and `body` fields of the correct types, visiting this 76 + link will prefill those fields with the values "Platypus" and "Ornithopter" 77 + respectively. 78 + 79 + The rest of this document shows which parameters you can add to this form and 80 + how to format them. 81 + 82 + 83 + Supported Fields 84 + ---------------- 85 + 86 + This form supports these fields: 87 + 88 + EOTEXT 89 + , 90 + $uri, 91 + $uri); 92 + 93 + $rows = array(); 94 + foreach ($fields as $field) { 95 + $rows[] = array( 96 + $field->getLabel(), 97 + $field->getKey(), 98 + $field->getHTTPParameterType(), 99 + $field->getDescription(), 100 + ); 101 + } 102 + 103 + $main_table = id(new AphrontTableView($rows)) 104 + ->setHeaders( 105 + array( 106 + pht('Label'), 107 + pht('Key'), 108 + pht('Type'), 109 + pht('Description'), 110 + )) 111 + ->setColumnClasses( 112 + array( 113 + 'pri', 114 + null, 115 + null, 116 + 'wide', 117 + )); 118 + 119 + $aliases_text = pht(<<<EOTEXT 120 + Aliases 121 + ------- 122 + 123 + Aliases are alternate recognized keys for a field. For example, a field with 124 + a complex key like `examplePHIDs` might be have a simple version of that key 125 + as an alias, like `example`. 126 + 127 + Aliases work just like the primary key when prefilling forms. They make it 128 + easier to remember and use HTTP parameters by providing more natural ways to do 129 + some prefilling. 130 + 131 + For example, if a field has `examplePHIDs` as a key but has aliases `example` 132 + and `examples`, these three URIs will all do the same thing: 133 + 134 + ``` 135 + %s?examplePHIDs=... 136 + %s?examples=... 137 + %s?example=... 138 + ``` 139 + 140 + If a URI specifies multiple default values for a field, the value using the 141 + primary key has precedence. Generally, you can not mix different aliases in 142 + a single URI. 143 + 144 + EOTEXT 145 + , 146 + $uri, 147 + $uri, 148 + $uri); 149 + 150 + $rows = array(); 151 + foreach ($fields as $field) { 152 + $aliases = $field->getAliases(); 153 + if (!$aliases) { 154 + continue; 155 + } 156 + $rows[] = array( 157 + $field->getLabel(), 158 + $field->getKey(), 159 + implode(', ', $aliases), 160 + ); 161 + } 162 + 163 + $alias_table = id(new AphrontTableView($rows)) 164 + ->setNoDataString(pht('This object has no fields with aliases.')) 165 + ->setHeaders( 166 + array( 167 + pht('Label'), 168 + pht('Key'), 169 + pht('Aliases'), 170 + )) 171 + ->setColumnClasses( 172 + array( 173 + 'pri', 174 + null, 175 + 'wide', 176 + )); 177 + 178 + $select_text = pht(<<<EOTEXT 179 + Select Fields 180 + ------------- 181 + 182 + Some fields support selection from a specific set of values. When prefilling 183 + these fields, use the value in the **Value** column to select the appropriate 184 + setting. 185 + 186 + EOTEXT 187 + ); 188 + 189 + $rows = array(); 190 + foreach ($fields as $field) { 191 + if (!($field instanceof PhabricatorSelectEditField)) { 192 + continue; 193 + } 194 + 195 + $options = $field->getOptions(); 196 + $label = $field->getLabel(); 197 + foreach ($options as $option_key => $option_value) { 198 + if (strlen($option_key)) { 199 + $option_display = $option_key; 200 + } else { 201 + $option_display = phutil_tag('em', array(), pht('<empty>')); 202 + } 203 + 204 + $rows[] = array( 205 + $label, 206 + $option_display, 207 + $option_value, 208 + ); 209 + $label = null; 210 + } 211 + } 212 + 213 + $select_table = id(new AphrontTableView($rows)) 214 + ->setNoDataString(pht('This object has no select fields.')) 215 + ->setHeaders( 216 + array( 217 + pht('Field'), 218 + pht('Value'), 219 + pht('Label'), 220 + )) 221 + ->setColumnClasses( 222 + array( 223 + 'pri', 224 + null, 225 + 'wide', 226 + )); 227 + 228 + $types_text = pht(<<<EOTEXT 229 + Field Types 230 + ----------- 231 + 232 + Fields in this form have the types described in the table below. This table 233 + shows how to format values for each field type. 234 + EOTEXT 235 + ); 236 + 237 + // TODO: This should be formalized and modularized. 238 + $type_spec = array( 239 + 'string' => array( 240 + 'format' => pht('URL encoded text.'), 241 + 'examples' => array( 242 + 'v=simple', 243 + 'v=properly%20escaped%20text', 244 + ), 245 + ), 246 + 'select' => array( 247 + 'format' => pht('Value from allowed set.'), 248 + 'examples' => array( 249 + 'v=value', 250 + ), 251 + ), 252 + 'list<phid>' => array( 253 + 'format' => array( 254 + pht('Comma-separated list of PHIDs.'), 255 + pht('List of PHIDs, as array.'), 256 + ), 257 + 'examples' => array( 258 + 'v=PHID-XXXX-1111,PHID-XXXX-2222', 259 + 'v[]=PHID-XXXX-1111&v[]=PHID-XXXX-2222', 260 + ), 261 + ), 262 + 'phid' => array( 263 + 'format' => pht('Single PHID.'), 264 + 'examples' => pht('v=PHID-XXX-1111'), 265 + ), 266 + ); 267 + 268 + $rows = array(); 269 + $br = phutil_tag('br'); 270 + foreach ($types as $type => $fields) { 271 + $spec = idx($type_spec, $type, array()); 272 + 273 + $field_list = mpull($fields, 'getKey'); 274 + $field_list = phutil_implode_html($br, $field_list); 275 + 276 + $format_list = idx($spec, 'format', array()); 277 + $format_list = phutil_implode_html($br, (array)$format_list); 278 + 279 + $example_list = idx($spec, 'examples', array()); 280 + $example_list = phutil_implode_html($br, (array)$example_list); 281 + 282 + $rows[] = array( 283 + $type, 284 + $field_list, 285 + $format_list, 286 + $example_list, 287 + ); 288 + } 289 + 290 + $types_table = id(new AphrontTableView($rows)) 291 + ->setNoDataString(pht('This object has no fields with types.')) 292 + ->setHeaders( 293 + array( 294 + pht('Type'), 295 + pht('Fields'), 296 + pht('Formats'), 297 + pht('Examples'), 298 + )) 299 + ->setColumnClasses( 300 + array( 301 + 'pri top', 302 + 'top', 303 + 'top', 304 + 'wide top prewrap', 305 + )); 306 + 307 + return array( 308 + $this->renderInstructions($intro), 309 + $this->renderTable($main_table), 310 + $this->renderInstructions($aliases_text), 311 + $this->renderTable($alias_table), 312 + $this->renderInstructions($select_text), 313 + $this->renderTable($select_table), 314 + $this->renderInstructions($types_text), 315 + $this->renderTable($types_table), 316 + ); 317 + } 318 + 319 + protected function renderTable(AphrontTableView $table) { 320 + return id(new PHUIBoxView()) 321 + ->addMargin(PHUI::MARGIN_LARGE_LEFT) 322 + ->addMargin(PHUI::MARGIN_LARGE_RIGHT) 323 + ->addMargin(PHUI::MARGIN_LARGE_BOTTOM) 324 + ->appendChild($table); 325 + } 326 + 327 + protected function renderInstructions($corpus) { 328 + $viewer = $this->getUser(); 329 + 330 + return id(new PHUIBoxView()) 331 + ->addMargin(PHUI::MARGIN_SMALL_TOP) 332 + ->addMargin(PHUI::MARGIN_SMALL_BOTTOM) 333 + ->appendChild(new PHUIRemarkupView($viewer, $corpus)); 334 + } 335 + 336 + }
+4
webroot/rsrc/css/aphront/table-view.css
··· 155 155 color: {$darkbluetext}; 156 156 } 157 157 158 + .aphront-table-view td.top { 159 + vertical-align: top; 160 + } 161 + 158 162 .aphront-table-view td.wide { 159 163 white-space: normal; 160 164 width: 100%;