From 3c1f393c812fe299b916d20523c1ad1164f011a5 Mon Sep 17 00:00:00 2001 From: epriestley Date: Fri, 1 May 2020 06:00:37 -0700 Subject: [PATCH] When a Paste has a useful alternative rendering in Files, provide a hint Summary: Ref T13528. When a file in Paste (like a Jupyter notebook) has a good/useful document engine, provide a link to Files. Test Plan: {F7409881} Maniphest Tasks: T13528 Differential Revision: https://secure.phabricator.com/D21196 --- .../console/core/DarkConsoleCore.php | 2 + .../document/PhabricatorDocumentEngine.php | 4 ++ .../PhabricatorJupyterDocumentEngine.php | 4 ++ .../PhabricatorDocumentRenderingEngine.php | 6 ++ .../PhabricatorPasteViewController.php | 63 ++++++++++++++++++- 5 files changed, 76 insertions(+), 3 deletions(-) diff --git a/src/applications/console/core/DarkConsoleCore.php b/src/applications/console/core/DarkConsoleCore.php index ddb22b9cfe..437d6f0be7 100644 --- a/src/applications/console/core/DarkConsoleCore.php +++ b/src/applications/console/core/DarkConsoleCore.php @@ -121,6 +121,8 @@ final class DarkConsoleCore extends Phobject { $data[$key] = $this->sanitizeForJSON($value); } return $data; + } else if (is_resource($data)) { + return ''; } else { // Truncate huge strings. Since the data doesn't really matter much, // just truncate bytes to avoid PhutilUTF8StringTruncator overhead. diff --git a/src/applications/files/document/PhabricatorDocumentEngine.php b/src/applications/files/document/PhabricatorDocumentEngine.php index 9593e1d98d..3a13c5eb4a 100644 --- a/src/applications/files/document/PhabricatorDocumentEngine.php +++ b/src/applications/files/document/PhabricatorDocumentEngine.php @@ -281,4 +281,8 @@ abstract class PhabricatorDocumentEngine )); } + public function shouldSuggestEngine(PhabricatorDocumentRef $ref) { + return false; + } + } diff --git a/src/applications/files/document/PhabricatorJupyterDocumentEngine.php b/src/applications/files/document/PhabricatorJupyterDocumentEngine.php index 834a880b42..3e479fdace 100644 --- a/src/applications/files/document/PhabricatorJupyterDocumentEngine.php +++ b/src/applications/files/document/PhabricatorJupyterDocumentEngine.php @@ -748,4 +748,8 @@ final class PhabricatorJupyterDocumentEngine return $content; } + public function shouldSuggestEngine(PhabricatorDocumentRef $ref) { + return true; + } + } diff --git a/src/applications/files/document/render/PhabricatorDocumentRenderingEngine.php b/src/applications/files/document/render/PhabricatorDocumentRenderingEngine.php index 2524f77821..5a4cb77340 100644 --- a/src/applications/files/document/render/PhabricatorDocumentRenderingEngine.php +++ b/src/applications/files/document/render/PhabricatorDocumentRenderingEngine.php @@ -305,6 +305,12 @@ abstract class PhabricatorDocumentRenderingEngine return $crumbs; } + public function getRefViewURI( + PhabricatorDocumentRef $ref, + PhabricatorDocumentEngine $engine) { + return $this->newRefViewURI($ref, $engine); + } + abstract protected function newRefViewURI( PhabricatorDocumentRef $ref, PhabricatorDocumentEngine $engine); diff --git a/src/applications/paste/controller/PhabricatorPasteViewController.php b/src/applications/paste/controller/PhabricatorPasteViewController.php index 9b4079fd46..b5736b784e 100644 --- a/src/applications/paste/controller/PhabricatorPasteViewController.php +++ b/src/applications/paste/controller/PhabricatorPasteViewController.php @@ -51,16 +51,19 @@ final class PhabricatorPasteViewController extends PhabricatorPasteController { $timeline->setQuoteRef($monogram); $comment_view->setTransactionTimeline($timeline); + $recommendation_view = $this->newDocumentRecommendationView($paste); + $paste_view = id(new PHUITwoColumnView()) ->setHeader($header) ->setSubheader($subheader) - ->setMainColumn(array( + ->setMainColumn( + array( + $recommendation_view, $source_code, $timeline, $comment_view, )) - ->setCurtain($curtain) - ->addClass('ponder-question-view'); + ->setCurtain($curtain); return $this->newPage() ->setTitle($paste->getFullName()) @@ -170,4 +173,58 @@ final class PhabricatorPasteViewController extends PhabricatorPasteController { ->setContent($content); } + private function newDocumentRecommendationView(PhabricatorPaste $paste) { + $viewer = $this->getViewer(); + + // See PHI1703. If a viewer is looking at a document in Paste which has + // a good rendering via a DocumentEngine, suggest they view the content + // in Files instead so they can see it rendered. + + $ref = id(new PhabricatorDocumentRef()) + ->setName($paste->getTitle()) + ->setData($paste->getRawContent()); + + $engines = PhabricatorDocumentEngine::getEnginesForRef($viewer, $ref); + if (!$engines) { + return null; + } + + $engine = head($engines); + if (!$engine->shouldSuggestEngine($ref)) { + return null; + } + + $file = id(new PhabricatorFileQuery()) + ->setViewer($viewer) + ->withPHIDs(array($paste->getFilePHID())) + ->executeOne(); + if (!$file) { + return null; + } + + $file_ref = id(new PhabricatorDocumentRef()) + ->setFile($file); + + $view_uri = id(new PhabricatorFileDocumentRenderingEngine()) + ->getRefViewURI($file_ref, $engine); + + $view_as_label = $engine->getViewAsLabel($file_ref); + + $view_as_hint = pht( + 'This content can be rendered as a document in Files.'); + + return id(new PHUIInfoView()) + ->setSeverity(PHUIInfoView::SEVERITY_NOTICE) + ->addButton( + id(new PHUIButtonView()) + ->setTag('a') + ->setText($view_as_label) + ->setHref($view_uri) + ->setColor('grey')) + ->setErrors( + array( + $view_as_hint, + )); + } + }