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

Update "Files" attachment table to show more attachment details and support detachment

Summary: Ref T13682. Make the "Attached" list in Files a bit more detailed, and add a "Detach" button.

Test Plan: Tried to detach unrelated, referenced, and attached files. Saw attached files detach.

Maniphest Tasks: T13682

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

+231 -17
+2
src/__phutil_library_map__.php
··· 3464 3464 'PhabricatorFileDataController' => 'applications/files/controller/PhabricatorFileDataController.php', 3465 3465 'PhabricatorFileDeleteController' => 'applications/files/controller/PhabricatorFileDeleteController.php', 3466 3466 'PhabricatorFileDeleteTransaction' => 'applications/files/xaction/PhabricatorFileDeleteTransaction.php', 3467 + 'PhabricatorFileDetachController' => 'applications/files/controller/PhabricatorFileDetachController.php', 3467 3468 'PhabricatorFileDocumentController' => 'applications/files/controller/PhabricatorFileDocumentController.php', 3468 3469 'PhabricatorFileDocumentRenderingEngine' => 'applications/files/document/render/PhabricatorFileDocumentRenderingEngine.php', 3469 3470 'PhabricatorFileDropUploadController' => 'applications/files/controller/PhabricatorFileDropUploadController.php', ··· 9919 9920 'PhabricatorFileDataController' => 'PhabricatorFileController', 9920 9921 'PhabricatorFileDeleteController' => 'PhabricatorFileController', 9921 9922 'PhabricatorFileDeleteTransaction' => 'PhabricatorFileTransactionType', 9923 + 'PhabricatorFileDetachController' => 'PhabricatorFileController', 9922 9924 'PhabricatorFileDocumentController' => 'PhabricatorFileController', 9923 9925 'PhabricatorFileDocumentRenderingEngine' => 'PhabricatorDocumentRenderingEngine', 9924 9926 'PhabricatorFileDropUploadController' => 'PhabricatorFileController',
+2
src/applications/files/application/PhabricatorFilesApplication.php
··· 96 96 'document/(?P<engineKey>[^/]+)/(?P<phid>[^/]+)/' 97 97 => 'PhabricatorFileDocumentController', 98 98 'ui/' => array( 99 + 'detach/(?P<objectPHID>[^/]+)/(?P<filePHID>[^/]+)/' 100 + => 'PhabricatorFileDetachController', 99 101 'curtain/' => array( 100 102 'list/(?P<phid>[^/]+)/' 101 103 => 'PhabricatorFileUICurtainListController',
+120
src/applications/files/controller/PhabricatorFileDetachController.php
··· 1 + <?php 2 + 3 + final class PhabricatorFileDetachController 4 + extends PhabricatorFileController { 5 + 6 + public function handleRequest(AphrontRequest $request) { 7 + $viewer = $request->getViewer(); 8 + 9 + $object_phid = $request->getURIData('objectPHID'); 10 + $file_phid = $request->getURIData('filePHID'); 11 + 12 + $object = id(new PhabricatorObjectQuery()) 13 + ->setViewer($viewer) 14 + ->withPHIDs(array($object_phid)) 15 + ->executeOne(); 16 + if (!$object) { 17 + return new Aphront404Response(); 18 + } 19 + 20 + $handles = $viewer->loadHandles( 21 + array( 22 + $object_phid, 23 + $file_phid, 24 + )); 25 + 26 + $object_handle = $handles[$object_phid]; 27 + $file_handle = $handles[$file_phid]; 28 + $cancel_uri = $file_handle->getURI(); 29 + 30 + $dialog = $this->newDialog() 31 + ->setViewer($viewer) 32 + ->setTitle(pht('Detach File')) 33 + ->addCancelButton($cancel_uri, pht('Close')); 34 + 35 + $file_link = phutil_tag('strong', array(), $file_handle->renderLink()); 36 + $object_link = phutil_tag('strong', array(), $object_handle->renderLink()); 37 + 38 + $attachment = id(new PhabricatorFileAttachmentQuery()) 39 + ->setViewer($viewer) 40 + ->withObjectPHIDs(array($object->getPHID())) 41 + ->withFilePHIDs(array($file_phid)) 42 + ->needFiles(true) 43 + ->withVisibleFiles(true) 44 + ->executeOne(); 45 + if (!$attachment) { 46 + $body = pht( 47 + 'The file %s is not attached to the object %s.', 48 + $file_link, 49 + $object_link); 50 + 51 + return $dialog->appendParagraph($body); 52 + } 53 + 54 + $mode_reference = PhabricatorFileAttachment::MODE_REFERENCE; 55 + if ($attachment->getAttachmentMode() === $mode_reference) { 56 + $body = pht( 57 + 'The file %s is referenced by the object %s, but not attached to '. 58 + 'it, so it can not be detached.', 59 + $file_link, 60 + $object_link); 61 + 62 + return $dialog->appendParagraph($body); 63 + } 64 + 65 + if (!$attachment->canDetach()) { 66 + $body = pht( 67 + 'The file %s can not be detached from the object %s.', 68 + $file_link, 69 + $object_link); 70 + 71 + return $dialog->appendParagraph($body); 72 + } 73 + 74 + if (!$request->isDialogFormPost()) { 75 + $dialog->appendParagraph( 76 + pht( 77 + 'Detach the file %s from the object %s?', 78 + $file_link, 79 + $object_link)); 80 + 81 + $dialog->addSubmitButton(pht('Detach File')); 82 + 83 + return $dialog; 84 + } 85 + 86 + if (!($object instanceof PhabricatorApplicationTransactionInterface)) { 87 + $dialog->appendParagraph( 88 + pht( 89 + 'This object (of class "%s") does not implement the required '. 90 + 'interface ("%s"), so files can not be manually detached from it.', 91 + get_class($object), 92 + 'PhabricatorApplicationTransactionInterface')); 93 + 94 + return $dialog; 95 + } 96 + 97 + $editor = $object->getApplicationTransactionEditor() 98 + ->setActor($viewer) 99 + ->setContentSourceFromRequest($request) 100 + ->setContinueOnNoEffect(true) 101 + ->setContinueOnMissingFields(true); 102 + 103 + $template = $object->getApplicationTransactionTemplate(); 104 + 105 + $xactions = array(); 106 + 107 + $xactions[] = id(clone $template) 108 + ->setTransactionType(PhabricatorTransactions::TYPE_FILE) 109 + ->setNewValue( 110 + array( 111 + $file_phid => PhabricatorFileAttachment::MODE_DETACH, 112 + )); 113 + 114 + $editor->applyTransactions($object, $xactions); 115 + 116 + return $this->newRedirect() 117 + ->setURI($cancel_uri); 118 + } 119 + 120 + }
+1 -4
src/applications/files/controller/PhabricatorFileUICurtainAttachController.php
··· 28 28 return new Aphront404Response(); 29 29 } 30 30 31 - $file = $attachment->getFile(); 32 - $file_phid = $file->getPHID(); 33 - 34 31 $handles = $viewer->loadHandles( 35 32 array( 36 33 $object_phid, ··· 44 41 $dialog = $this->newDialog() 45 42 ->setViewer($viewer) 46 43 ->setTitle(pht('Attach File')) 47 - ->addCancelButton($object_handle->getURI(), pht('Close')); 44 + ->addCancelButton($cancel_uri, pht('Close')); 48 45 49 46 $file_link = phutil_tag('strong', array(), $file_handle->renderLink()); 50 47 $object_link = phutil_tag('strong', array(), $object_handle->renderLink());
+83 -13
src/applications/files/controller/PhabricatorFileViewController.php
··· 320 320 $finfo->addProperty(pht('Default Alt Text'), $default_alt); 321 321 } 322 322 323 - $phids = $file->getObjectPHIDs(); 324 - if ($phids) { 325 - $attached = new PHUIPropertyListView(); 323 + $attachments_table = $this->newAttachmentsView($file); 326 324 327 - $tab_group->addTab( 328 - id(new PHUITabView()) 329 - ->setName(pht('Attached')) 330 - ->setKey('attached') 331 - ->appendChild($attached)); 332 - 333 - $attached->addProperty( 334 - pht('Attached To'), 335 - $viewer->renderHandleList($phids)); 336 - } 325 + $tab_group->addTab( 326 + id(new PHUITabView()) 327 + ->setName(pht('Attached')) 328 + ->setKey('attached') 329 + ->appendChild($attachments_table)); 337 330 338 331 $engine = $this->loadStorageEngine($file); 339 332 if ($engine) { ··· 419 412 420 413 return $engine->newDocumentView($ref); 421 414 } 415 + 416 + private function newAttachmentsView(PhabricatorFile $file) { 417 + $viewer = $this->getViewer(); 418 + 419 + $attachments = id(new PhabricatorFileAttachmentQuery()) 420 + ->setViewer($viewer) 421 + ->withFilePHIDs(array($file->getPHID())) 422 + ->execute(); 423 + 424 + $handles = $viewer->loadHandles(mpull($attachments, 'getObjectPHID')); 425 + 426 + $rows = array(); 427 + 428 + $mode_map = PhabricatorFileAttachment::getModeNameMap(); 429 + $mode_attach = PhabricatorFileAttachment::MODE_ATTACH; 430 + 431 + foreach ($attachments as $attachment) { 432 + $object_phid = $attachment->getObjectPHID(); 433 + $handle = $handles[$object_phid]; 434 + 435 + $attachment_mode = $attachment->getAttachmentMode(); 436 + 437 + $mode_name = idx($mode_map, $attachment_mode); 438 + if ($mode_name === null) { 439 + $mode_name = pht('Unknown ("%s")', $attachment_mode); 440 + } 441 + 442 + $detach_uri = urisprintf( 443 + '/file/ui/detach/%s/%s/', 444 + $object_phid, 445 + $file->getPHID()); 446 + 447 + $is_disabled = !$attachment->canDetach(); 448 + 449 + $detach_button = id(new PHUIButtonView()) 450 + ->setHref($detach_uri) 451 + ->setTag('a') 452 + ->setWorkflow(true) 453 + ->setDisabled($is_disabled) 454 + ->setColor(PHUIButtonView::GREY) 455 + ->setSize(PHUIButtonView::SMALL) 456 + ->setText(pht('Detach File')); 457 + 458 + javelin_tag( 459 + 'a', 460 + array( 461 + 'href' => $detach_uri, 462 + 'sigil' => 'workflow', 463 + 'disabled' => true, 464 + 'class' => 'small button button-grey disabled', 465 + ), 466 + pht('Detach File')); 467 + 468 + $rows[] = array( 469 + $handle->renderLink(), 470 + $mode_name, 471 + $detach_button, 472 + ); 473 + } 474 + 475 + $table = id(new AphrontTableView($rows)) 476 + ->setHeaders( 477 + array( 478 + pht('Attached To'), 479 + pht('Mode'), 480 + null, 481 + )) 482 + ->setColumnClasses( 483 + array( 484 + 'pri wide', 485 + null, 486 + null, 487 + )); 488 + 489 + return $table; 490 + } 491 + 422 492 423 493 }
+16
src/applications/files/storage/PhabricatorFileAttachment.php
··· 46 46 ); 47 47 } 48 48 49 + public static function getModeNameMap() { 50 + return array( 51 + self::MODE_ATTACH => pht('Attached'), 52 + self::MODE_REFERENCE => pht('Referenced'), 53 + ); 54 + } 55 + 49 56 public function isPolicyAttachment() { 50 57 switch ($this->getAttachmentMode()) { 51 58 case self::MODE_ATTACH: ··· 71 78 72 79 public function getFile() { 73 80 return $this->assertAttached($this->file); 81 + } 82 + 83 + public function canDetach() { 84 + switch ($this->getAttachmentMode()) { 85 + case self::MODE_ATTACH: 86 + return true; 87 + } 88 + 89 + return false; 74 90 } 75 91 76 92
+7
src/infrastructure/internationalization/translation/PhabricatorUSEnglishTranslation.php
··· 1803 1803 ), 1804 1804 ), 1805 1805 1806 + '%s removed %s attached file(s): %s.' => array( 1807 + array( 1808 + '%s removed an attached file: %3$s.', 1809 + '%s removed attached files: %3$s.', 1810 + ), 1811 + ), 1812 + 1806 1813 ); 1807 1814 } 1808 1815