1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-25 16:22:43 +01:00

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
This commit is contained in:
epriestley 2022-05-25 12:45:18 -07:00
parent 5aa159a830
commit 7e5f7b9640
7 changed files with 231 additions and 17 deletions

View file

@ -3464,6 +3464,7 @@ phutil_register_library_map(array(
'PhabricatorFileDataController' => 'applications/files/controller/PhabricatorFileDataController.php',
'PhabricatorFileDeleteController' => 'applications/files/controller/PhabricatorFileDeleteController.php',
'PhabricatorFileDeleteTransaction' => 'applications/files/xaction/PhabricatorFileDeleteTransaction.php',
'PhabricatorFileDetachController' => 'applications/files/controller/PhabricatorFileDetachController.php',
'PhabricatorFileDocumentController' => 'applications/files/controller/PhabricatorFileDocumentController.php',
'PhabricatorFileDocumentRenderingEngine' => 'applications/files/document/render/PhabricatorFileDocumentRenderingEngine.php',
'PhabricatorFileDropUploadController' => 'applications/files/controller/PhabricatorFileDropUploadController.php',
@ -9919,6 +9920,7 @@ phutil_register_library_map(array(
'PhabricatorFileDataController' => 'PhabricatorFileController',
'PhabricatorFileDeleteController' => 'PhabricatorFileController',
'PhabricatorFileDeleteTransaction' => 'PhabricatorFileTransactionType',
'PhabricatorFileDetachController' => 'PhabricatorFileController',
'PhabricatorFileDocumentController' => 'PhabricatorFileController',
'PhabricatorFileDocumentRenderingEngine' => 'PhabricatorDocumentRenderingEngine',
'PhabricatorFileDropUploadController' => 'PhabricatorFileController',

View file

@ -96,6 +96,8 @@ final class PhabricatorFilesApplication extends PhabricatorApplication {
'document/(?P<engineKey>[^/]+)/(?P<phid>[^/]+)/'
=> 'PhabricatorFileDocumentController',
'ui/' => array(
'detach/(?P<objectPHID>[^/]+)/(?P<filePHID>[^/]+)/'
=> 'PhabricatorFileDetachController',
'curtain/' => array(
'list/(?P<phid>[^/]+)/'
=> 'PhabricatorFileUICurtainListController',

View file

@ -0,0 +1,120 @@
<?php
final class PhabricatorFileDetachController
extends PhabricatorFileController {
public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer();
$object_phid = $request->getURIData('objectPHID');
$file_phid = $request->getURIData('filePHID');
$object = id(new PhabricatorObjectQuery())
->setViewer($viewer)
->withPHIDs(array($object_phid))
->executeOne();
if (!$object) {
return new Aphront404Response();
}
$handles = $viewer->loadHandles(
array(
$object_phid,
$file_phid,
));
$object_handle = $handles[$object_phid];
$file_handle = $handles[$file_phid];
$cancel_uri = $file_handle->getURI();
$dialog = $this->newDialog()
->setViewer($viewer)
->setTitle(pht('Detach File'))
->addCancelButton($cancel_uri, pht('Close'));
$file_link = phutil_tag('strong', array(), $file_handle->renderLink());
$object_link = phutil_tag('strong', array(), $object_handle->renderLink());
$attachment = id(new PhabricatorFileAttachmentQuery())
->setViewer($viewer)
->withObjectPHIDs(array($object->getPHID()))
->withFilePHIDs(array($file_phid))
->needFiles(true)
->withVisibleFiles(true)
->executeOne();
if (!$attachment) {
$body = pht(
'The file %s is not attached to the object %s.',
$file_link,
$object_link);
return $dialog->appendParagraph($body);
}
$mode_reference = PhabricatorFileAttachment::MODE_REFERENCE;
if ($attachment->getAttachmentMode() === $mode_reference) {
$body = pht(
'The file %s is referenced by the object %s, but not attached to '.
'it, so it can not be detached.',
$file_link,
$object_link);
return $dialog->appendParagraph($body);
}
if (!$attachment->canDetach()) {
$body = pht(
'The file %s can not be detached from the object %s.',
$file_link,
$object_link);
return $dialog->appendParagraph($body);
}
if (!$request->isDialogFormPost()) {
$dialog->appendParagraph(
pht(
'Detach the file %s from the object %s?',
$file_link,
$object_link));
$dialog->addSubmitButton(pht('Detach File'));
return $dialog;
}
if (!($object instanceof PhabricatorApplicationTransactionInterface)) {
$dialog->appendParagraph(
pht(
'This object (of class "%s") does not implement the required '.
'interface ("%s"), so files can not be manually detached from it.',
get_class($object),
'PhabricatorApplicationTransactionInterface'));
return $dialog;
}
$editor = $object->getApplicationTransactionEditor()
->setActor($viewer)
->setContentSourceFromRequest($request)
->setContinueOnNoEffect(true)
->setContinueOnMissingFields(true);
$template = $object->getApplicationTransactionTemplate();
$xactions = array();
$xactions[] = id(clone $template)
->setTransactionType(PhabricatorTransactions::TYPE_FILE)
->setNewValue(
array(
$file_phid => PhabricatorFileAttachment::MODE_DETACH,
));
$editor->applyTransactions($object, $xactions);
return $this->newRedirect()
->setURI($cancel_uri);
}
}

View file

@ -28,9 +28,6 @@ final class PhabricatorFileUICurtainAttachController
return new Aphront404Response();
}
$file = $attachment->getFile();
$file_phid = $file->getPHID();
$handles = $viewer->loadHandles(
array(
$object_phid,
@ -44,7 +41,7 @@ final class PhabricatorFileUICurtainAttachController
$dialog = $this->newDialog()
->setViewer($viewer)
->setTitle(pht('Attach File'))
->addCancelButton($object_handle->getURI(), pht('Close'));
->addCancelButton($cancel_uri, pht('Close'));
$file_link = phutil_tag('strong', array(), $file_handle->renderLink());
$object_link = phutil_tag('strong', array(), $object_handle->renderLink());

View file

@ -320,20 +320,13 @@ final class PhabricatorFileViewController extends PhabricatorFileController {
$finfo->addProperty(pht('Default Alt Text'), $default_alt);
}
$phids = $file->getObjectPHIDs();
if ($phids) {
$attached = new PHUIPropertyListView();
$attachments_table = $this->newAttachmentsView($file);
$tab_group->addTab(
id(new PHUITabView())
->setName(pht('Attached'))
->setKey('attached')
->appendChild($attached));
$attached->addProperty(
pht('Attached To'),
$viewer->renderHandleList($phids));
}
$tab_group->addTab(
id(new PHUITabView())
->setName(pht('Attached'))
->setKey('attached')
->appendChild($attachments_table));
$engine = $this->loadStorageEngine($file);
if ($engine) {
@ -420,4 +413,81 @@ final class PhabricatorFileViewController extends PhabricatorFileController {
return $engine->newDocumentView($ref);
}
private function newAttachmentsView(PhabricatorFile $file) {
$viewer = $this->getViewer();
$attachments = id(new PhabricatorFileAttachmentQuery())
->setViewer($viewer)
->withFilePHIDs(array($file->getPHID()))
->execute();
$handles = $viewer->loadHandles(mpull($attachments, 'getObjectPHID'));
$rows = array();
$mode_map = PhabricatorFileAttachment::getModeNameMap();
$mode_attach = PhabricatorFileAttachment::MODE_ATTACH;
foreach ($attachments as $attachment) {
$object_phid = $attachment->getObjectPHID();
$handle = $handles[$object_phid];
$attachment_mode = $attachment->getAttachmentMode();
$mode_name = idx($mode_map, $attachment_mode);
if ($mode_name === null) {
$mode_name = pht('Unknown ("%s")', $attachment_mode);
}
$detach_uri = urisprintf(
'/file/ui/detach/%s/%s/',
$object_phid,
$file->getPHID());
$is_disabled = !$attachment->canDetach();
$detach_button = id(new PHUIButtonView())
->setHref($detach_uri)
->setTag('a')
->setWorkflow(true)
->setDisabled($is_disabled)
->setColor(PHUIButtonView::GREY)
->setSize(PHUIButtonView::SMALL)
->setText(pht('Detach File'));
javelin_tag(
'a',
array(
'href' => $detach_uri,
'sigil' => 'workflow',
'disabled' => true,
'class' => 'small button button-grey disabled',
),
pht('Detach File'));
$rows[] = array(
$handle->renderLink(),
$mode_name,
$detach_button,
);
}
$table = id(new AphrontTableView($rows))
->setHeaders(
array(
pht('Attached To'),
pht('Mode'),
null,
))
->setColumnClasses(
array(
'pri wide',
null,
null,
));
return $table;
}
}

View file

@ -46,6 +46,13 @@ final class PhabricatorFileAttachment
);
}
public static function getModeNameMap() {
return array(
self::MODE_ATTACH => pht('Attached'),
self::MODE_REFERENCE => pht('Referenced'),
);
}
public function isPolicyAttachment() {
switch ($this->getAttachmentMode()) {
case self::MODE_ATTACH:
@ -73,6 +80,15 @@ final class PhabricatorFileAttachment
return $this->assertAttached($this->file);
}
public function canDetach() {
switch ($this->getAttachmentMode()) {
case self::MODE_ATTACH:
return true;
}
return false;
}
/* -( PhabricatorPolicyInterface )----------------------------------------- */

View file

@ -1803,6 +1803,13 @@ final class PhabricatorUSEnglishTranslation
),
),
'%s removed %s attached file(s): %s.' => array(
array(
'%s removed an attached file: %3$s.',
'%s removed attached files: %3$s.',
),
),
);
}