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

Somewhat give Phriction the new Breadcrumb UI.

Summary:
Okay, just a forewarning, this is horrible right now.

But I think it's an okay enough start that it's worth sending what I've done.

This rips out the old Phriction breadcrumb UI and replaces it with the new one
that other apps have been starting to use.

Test Plan: Looked at a bunch of Phriction pages.

Reviewers: epriestley

CC: aran, Korvin

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

authored by

Ricky Elrod and committed by
epriestley
368657a5 16a0f4a8

+217 -163
+42 -42
src/__celerity_resource_map__.php
··· 632 632 ), 633 633 'aphront-form-view-css' => 634 634 array( 635 - 'uri' => '/res/6f1739eb/rsrc/css/aphront/form-view.css', 635 + 'uri' => '/res/cd15aff5/rsrc/css/aphront/form-view.css', 636 636 'type' => 'css', 637 637 'requires' => 638 638 array( ··· 3246 3246 ), array( 3247 3247 'packages' => 3248 3248 array( 3249 - '6e748adf' => 3249 + '367c20f1' => 3250 3250 array( 3251 3251 'name' => 'core.pkg.css', 3252 3252 'symbols' => ··· 3291 3291 37 => 'phabricator-object-item-list-view-css', 3292 3292 38 => 'global-drag-and-drop-css', 3293 3293 ), 3294 - 'uri' => '/res/pkg/6e748adf/core.pkg.css', 3294 + 'uri' => '/res/pkg/367c20f1/core.pkg.css', 3295 3295 'type' => 'css', 3296 3296 ), 3297 3297 '2921e259' => ··· 3480 3480 'reverse' => 3481 3481 array( 3482 3482 'aphront-attached-file-view-css' => 'ac211174', 3483 - 'aphront-crumbs-view-css' => '6e748adf', 3484 - 'aphront-dialog-view-css' => '6e748adf', 3485 - 'aphront-error-view-css' => '6e748adf', 3486 - 'aphront-form-view-css' => '6e748adf', 3483 + 'aphront-crumbs-view-css' => '367c20f1', 3484 + 'aphront-dialog-view-css' => '367c20f1', 3485 + 'aphront-error-view-css' => '367c20f1', 3486 + 'aphront-form-view-css' => '367c20f1', 3487 3487 'aphront-headsup-action-list-view-css' => '20933a11', 3488 - 'aphront-headsup-view-css' => '6e748adf', 3489 - 'aphront-list-filter-view-css' => '6e748adf', 3490 - 'aphront-pager-view-css' => '6e748adf', 3491 - 'aphront-panel-view-css' => '6e748adf', 3492 - 'aphront-table-view-css' => '6e748adf', 3493 - 'aphront-tokenizer-control-css' => '6e748adf', 3494 - 'aphront-tooltip-css' => '6e748adf', 3495 - 'aphront-typeahead-control-css' => '6e748adf', 3488 + 'aphront-headsup-view-css' => '367c20f1', 3489 + 'aphront-list-filter-view-css' => '367c20f1', 3490 + 'aphront-pager-view-css' => '367c20f1', 3491 + 'aphront-panel-view-css' => '367c20f1', 3492 + 'aphront-table-view-css' => '367c20f1', 3493 + 'aphront-tokenizer-control-css' => '367c20f1', 3494 + 'aphront-tooltip-css' => '367c20f1', 3495 + 'aphront-typeahead-control-css' => '367c20f1', 3496 3496 'differential-changeset-view-css' => '20933a11', 3497 3497 'differential-core-view-css' => '20933a11', 3498 3498 'differential-inline-comment-editor' => '76556a8f', ··· 3506 3506 'differential-table-of-contents-css' => '20933a11', 3507 3507 'diffusion-commit-view-css' => 'c8ce2d88', 3508 3508 'diffusion-icons-css' => 'c8ce2d88', 3509 - 'global-drag-and-drop-css' => '6e748adf', 3509 + 'global-drag-and-drop-css' => '367c20f1', 3510 3510 'inline-comment-summary-css' => '20933a11', 3511 3511 'javelin-aphlict' => '2921e259', 3512 3512 'javelin-behavior' => 'fbeded59', ··· 3575 3575 'javelin-util' => 'fbeded59', 3576 3576 'javelin-vector' => 'fbeded59', 3577 3577 'javelin-workflow' => 'fbeded59', 3578 - 'lightbox-attachment-css' => '6e748adf', 3578 + 'lightbox-attachment-css' => '367c20f1', 3579 3579 'maniphest-task-summary-css' => 'ac211174', 3580 3580 'maniphest-transaction-detail-css' => 'ac211174', 3581 - 'phabricator-app-buttons-css' => '6e748adf', 3581 + 'phabricator-app-buttons-css' => '367c20f1', 3582 3582 'phabricator-busy' => '2921e259', 3583 3583 'phabricator-content-source-view-css' => '20933a11', 3584 - 'phabricator-core-buttons-css' => '6e748adf', 3585 - 'phabricator-core-css' => '6e748adf', 3586 - 'phabricator-crumbs-view-css' => '6e748adf', 3587 - 'phabricator-directory-css' => '6e748adf', 3584 + 'phabricator-core-buttons-css' => '367c20f1', 3585 + 'phabricator-core-css' => '367c20f1', 3586 + 'phabricator-crumbs-view-css' => '367c20f1', 3587 + 'phabricator-directory-css' => '367c20f1', 3588 3588 'phabricator-drag-and-drop-file-upload' => '76556a8f', 3589 3589 'phabricator-dropdown-menu' => '2921e259', 3590 3590 'phabricator-file-upload' => '2921e259', 3591 - 'phabricator-filetree-view-css' => '6e748adf', 3592 - 'phabricator-flag-css' => '6e748adf', 3593 - 'phabricator-form-view-css' => '6e748adf', 3594 - 'phabricator-header-view-css' => '6e748adf', 3595 - 'phabricator-jump-nav' => '6e748adf', 3591 + 'phabricator-filetree-view-css' => '367c20f1', 3592 + 'phabricator-flag-css' => '367c20f1', 3593 + 'phabricator-form-view-css' => '367c20f1', 3594 + 'phabricator-header-view-css' => '367c20f1', 3595 + 'phabricator-jump-nav' => '367c20f1', 3596 3596 'phabricator-keyboard-shortcut' => '2921e259', 3597 3597 'phabricator-keyboard-shortcut-manager' => '2921e259', 3598 - 'phabricator-main-menu-view' => '6e748adf', 3598 + 'phabricator-main-menu-view' => '367c20f1', 3599 3599 'phabricator-menu-item' => '2921e259', 3600 - 'phabricator-nav-view-css' => '6e748adf', 3600 + 'phabricator-nav-view-css' => '367c20f1', 3601 3601 'phabricator-notification' => '2921e259', 3602 - 'phabricator-notification-css' => '6e748adf', 3603 - 'phabricator-notification-menu-css' => '6e748adf', 3604 - 'phabricator-object-item-list-view-css' => '6e748adf', 3602 + 'phabricator-notification-css' => '367c20f1', 3603 + 'phabricator-notification-menu-css' => '367c20f1', 3604 + 'phabricator-object-item-list-view-css' => '367c20f1', 3605 3605 'phabricator-object-selector-css' => '20933a11', 3606 3606 'phabricator-paste-file-upload' => '2921e259', 3607 3607 'phabricator-prefab' => '2921e259', 3608 3608 'phabricator-project-tag-css' => 'ac211174', 3609 - 'phabricator-remarkup-css' => '6e748adf', 3609 + 'phabricator-remarkup-css' => '367c20f1', 3610 3610 'phabricator-shaped-request' => '76556a8f', 3611 - 'phabricator-side-menu-view-css' => '6e748adf', 3612 - 'phabricator-standard-page-view' => '6e748adf', 3611 + 'phabricator-side-menu-view-css' => '367c20f1', 3612 + 'phabricator-standard-page-view' => '367c20f1', 3613 3613 'phabricator-textareautils' => '2921e259', 3614 3614 'phabricator-tooltip' => '2921e259', 3615 - 'phabricator-transaction-view-css' => '6e748adf', 3616 - 'phabricator-zindex-css' => '6e748adf', 3617 - 'sprite-apps-large-css' => '6e748adf', 3618 - 'sprite-gradient-css' => '6e748adf', 3619 - 'sprite-icon-css' => '6e748adf', 3620 - 'sprite-menu-css' => '6e748adf', 3621 - 'syntax-highlighting-css' => '6e748adf', 3615 + 'phabricator-transaction-view-css' => '367c20f1', 3616 + 'phabricator-zindex-css' => '367c20f1', 3617 + 'sprite-apps-large-css' => '367c20f1', 3618 + 'sprite-gradient-css' => '367c20f1', 3619 + 'sprite-icon-css' => '367c20f1', 3620 + 'sprite-menu-css' => '367c20f1', 3621 + 'syntax-highlighting-css' => '367c20f1', 3622 3622 ), 3623 3623 ));
+77
src/applications/phriction/controller/PhrictionController.php
··· 20 20 $response = new AphrontWebpageResponse(); 21 21 return $response->setContent($page->render()); 22 22 } 23 + 24 + public function buildSideNavView($filter = null, $for_app = false) { 25 + $user = $this->getRequest()->getUser(); 26 + 27 + $nav = new AphrontSideNavFilterView(); 28 + $nav->setBaseURI(new PhutilURI('/phriction/list/')); 29 + 30 + if ($for_app) { 31 + $nav->addFilter('', pht('Root Document'), '/w/'); 32 + $nav->addFilter('', pht('Create Document'), '/phriction/new'); 33 + } 34 + 35 + $nav->addLabel('Filters'); 36 + $nav->addFilter('active', pht('Active Documents')); 37 + $nav->addFilter('all', pht('All Documents')); 38 + $nav->addFilter('updates', pht('Recently Updated')); 39 + 40 + $nav->selectFilter($filter, 'active'); 41 + 42 + return $nav; 43 + } 44 + 45 + public function buildApplicationMenu() { 46 + return $this->buildSideNavView(null, true)->getMenu(); 47 + } 48 + 49 + public function buildApplicationCrumbs() { 50 + $crumbs = parent::buildApplicationCrumbs(); 51 + 52 + $crumbs->addAction( 53 + id(new PhabricatorMenuItemView()) 54 + ->setName(pht('Create Document')) 55 + ->setHref('/phriction/new/') 56 + ->setIcon('create')); 57 + 58 + return $crumbs; 59 + } 60 + 61 + public function renderBreadcrumbs($slug) { 62 + $ancestor_handles = array(); 63 + $ancestral_slugs = PhabricatorSlug::getAncestry($slug); 64 + $ancestral_slugs[] = $slug; 65 + if ($ancestral_slugs) { 66 + $empty_slugs = array_fill_keys($ancestral_slugs, null); 67 + $ancestors = id(new PhrictionDocument())->loadAllWhere( 68 + 'slug IN (%Ls)', 69 + $ancestral_slugs); 70 + $ancestors = mpull($ancestors, null, 'getSlug'); 71 + 72 + $ancestor_phids = mpull($ancestors, 'getPHID'); 73 + $handles = array(); 74 + if ($ancestor_phids) { 75 + $handles = $this->loadViewerHandles($ancestor_phids); 76 + } 77 + 78 + $ancestor_handles = array(); 79 + foreach ($ancestral_slugs as $slug) { 80 + if (isset($ancestors[$slug])) { 81 + $ancestor_handles[] = $handles[$ancestors[$slug]->getPHID()]; 82 + } else { 83 + $handle = new PhabricatorObjectHandle(); 84 + $handle->setName(PhabricatorSlug::getDefaultTitle($slug)); 85 + $handle->setURI(PhrictionDocument::getSlugURI($slug)); 86 + $ancestor_handles[] = $handle; 87 + } 88 + } 89 + } 90 + 91 + $breadcrumbs = array(); 92 + foreach ($ancestor_handles as $ancestor_handle) { 93 + $breadcrumbs[] = id(new PhabricatorCrumbView()) 94 + ->setName($ancestor_handle->getName()) 95 + ->setHref($ancestor_handle->getUri()); 96 + } 97 + return $breadcrumbs; 98 + } 99 + 23 100 }
+50 -83
src/applications/phriction/controller/PhrictionDocumentController.php
··· 30 30 'slug = %s', 31 31 $slug); 32 32 33 - $breadcrumbs = $this->renderBreadcrumbs($slug); 34 33 $version_note = null; 35 34 36 35 if (!$document) { 36 + 37 + $document = new PhrictionDocument(); 37 38 38 39 if (PhrictionDocument::isProjectSlug($slug)) { 39 40 $project = id(new PhabricatorProject())->loadOneWhere( ··· 130 131 $handles[$project_phid]->renderLink().'.'; 131 132 } 132 133 133 - 134 + $index_link = phutil_render_tag( 135 + 'a', 136 + array( 137 + 'href' => '/phriction/', 138 + ), 139 + pht('Document Index')); 134 140 135 141 $byline = 136 142 '<div class="phriction-byline">'. ··· 157 163 158 164 $page_content = 159 165 '<div class="phriction-content">'. 166 + $index_link. 160 167 $byline. 161 168 $core_content. 162 169 '</div>'; 163 - 164 - $create_button = javelin_render_tag( 165 - 'a', 166 - array( 167 - 'href' => '/phriction/new/', 168 - 'class' => 'button green', 169 - 'sigil' => 'workflow', 170 - ), 171 - pht('New Document')); 172 - $edit_button = phutil_render_tag( 173 - 'a', 174 - array( 175 - 'href' => '/phriction/edit/'.$document->getID().'/', 176 - 'class' => 'button', 177 - ), 178 - pht('Edit Document')); 179 - $history_button = phutil_render_tag( 180 - 'a', 181 - array( 182 - 'href' => PhrictionDocument::getSlugURI($slug, 'history'), 183 - 'class' => 'button grey', 184 - ), 185 - pht('View History')); 186 - // these float right so history_button which is right most goes first 187 - $buttons = $history_button.$edit_button.$create_button; 188 170 } 189 171 190 172 if ($version_note) { ··· 193 175 194 176 $children = $this->renderChildren($slug); 195 177 178 + $crumbs = $this->buildApplicationCrumbs(); 179 + $crumb_views = $this->renderBreadcrumbs($slug); 180 + foreach ($crumb_views as $view) { 181 + $crumbs->addCrumb($view); 182 + } 183 + 184 + $actions = $this->buildActionView($user, $document); 185 + 186 + $header = id(new PhabricatorHeaderView()) 187 + ->setHeader($page_title); 188 + 196 189 $page = 197 - '<div class="phriction-header">'. 198 - $buttons. 199 - '<h1>'.phutil_escape_html($page_title).'</h1>'. 200 - $breadcrumbs. 201 - '</div>'. 190 + $crumbs->render(). 191 + $header->render(). 192 + $actions->render(). 202 193 $version_note. 203 194 $page_content. 204 195 $children; 205 196 206 - return $this->buildStandardPageResponse( 207 - $page, 197 + return $this->buildApplicationPage( 208 198 array( 209 - 'title' => 'Phriction - '.$page_title, 199 + $page, 200 + ), 201 + array( 202 + 'title' => $page_title, 203 + 'device' => true, 210 204 )); 211 205 212 206 } 213 207 214 - private function renderBreadcrumbs($slug) { 215 - 216 - $ancestor_handles = array(); 217 - $ancestral_slugs = PhabricatorSlug::getAncestry($slug); 218 - $ancestral_slugs[] = $slug; 219 - if ($ancestral_slugs) { 220 - $empty_slugs = array_fill_keys($ancestral_slugs, null); 221 - $ancestors = id(new PhrictionDocument())->loadAllWhere( 222 - 'slug IN (%Ls)', 223 - $ancestral_slugs); 224 - $ancestors = mpull($ancestors, null, 'getSlug'); 225 - 226 - $ancestor_phids = mpull($ancestors, 'getPHID'); 227 - $handles = array(); 228 - if ($ancestor_phids) { 229 - $handles = $this->loadViewerHandles($ancestor_phids); 230 - } 231 - 232 - $ancestor_handles = array(); 233 - foreach ($ancestral_slugs as $slug) { 234 - if (isset($ancestors[$slug])) { 235 - $ancestor_handles[] = $handles[$ancestors[$slug]->getPHID()]; 236 - } else { 237 - $handle = new PhabricatorObjectHandle(); 238 - $handle->setName(PhabricatorSlug::getDefaultTitle($slug)); 239 - $handle->setURI(PhrictionDocument::getSlugURI($slug)); 240 - $ancestor_handles[] = $handle; 241 - } 242 - } 243 - } 244 - 245 - $breadcrumbs = array(); 246 - foreach ($ancestor_handles as $ancestor_handle) { 247 - $breadcrumbs[] = $ancestor_handle->renderLink(); 248 - } 208 + private function buildActionView( 209 + PhabricatorUser $user, 210 + PhrictionDocument $document) { 211 + $can_edit = PhabricatorPolicyFilter::hasCapability( 212 + $user, 213 + $document, 214 + PhabricatorPolicyCapability::CAN_EDIT); 249 215 250 - $list = phutil_render_tag( 251 - 'a', 252 - array( 253 - 'href' => '/phriction/', 254 - ), 255 - 'Document Index'); 216 + $slug = PhabricatorSlug::normalize($this->slug); 256 217 257 - return 258 - '<div class="phriction-breadcrumbs">'. 259 - $list.' &middot; '. 260 - '<span class="phriction-document-crumbs">'. 261 - implode(" \xC2\xBB ", $breadcrumbs). 262 - '</span>'. 263 - '</div>'; 218 + return id(new PhabricatorActionListView()) 219 + ->setUser($user) 220 + ->setObject($document) 221 + ->addAction( 222 + id(new PhabricatorActionView()) 223 + ->setName(pht('Edit Document')) 224 + ->setIcon('edit') 225 + ->setHref('/phriction/edit/'.$document->getID().'/')) 226 + ->addAction( 227 + id(new PhabricatorActionView()) 228 + ->setName(pht('View History')) 229 + ->setIcon('history') 230 + ->setHref(PhrictionDocument::getSlugURI($slug, 'history'))); 264 231 } 265 232 266 233 private function renderChildren($slug) {
+13 -16
src/applications/phriction/controller/PhrictionHistoryController.php
··· 96 96 ); 97 97 } 98 98 99 - $crumbs = new AphrontCrumbsView(); 100 - $crumbs->setCrumbs( 101 - array( 102 - 'Phriction', 103 - phutil_render_tag( 104 - 'a', 105 - array( 106 - 'href' => PhrictionDocument::getSlugURI($document->getSlug()), 107 - ), 108 - phutil_escape_html($current->getTitle()) 109 - ), 110 - 'History', 111 - )); 112 - 113 - 114 99 $table = new AphrontTableView($rows); 115 100 $table->setHeaders( 116 101 array( ··· 135 120 '', 136 121 )); 137 122 123 + $crumbs = $this->buildApplicationCrumbs(); 124 + $crumb_views = $this->renderBreadcrumbs($document->getSlug()); 125 + foreach ($crumb_views as $view) { 126 + $crumbs->addCrumb($view); 127 + } 128 + $crumbs->addCrumb( 129 + id(new PhabricatorCrumbView()) 130 + ->setName(pht('History')) 131 + ->setHref( 132 + PhrictionDocument::getSlugURI($document->getSlug(), 'history'))); 133 + 138 134 $panel = new AphrontPanelView(); 139 135 $panel->setHeader('Document History'); 140 136 $panel->appendChild($table); 141 137 $panel->appendChild($pager); 142 138 143 - return $this->buildStandardPageResponse( 139 + return $this->buildApplicationPage( 144 140 array( 145 141 $crumbs, 146 142 $panel, 147 143 ), 148 144 array( 149 145 'title' => 'Document History', 146 + 'device' => true, 150 147 )); 151 148 152 149 }
+18 -21
src/applications/phriction/controller/PhrictionListController.php
··· 18 18 $user = $request->getUser(); 19 19 20 20 $views = array( 21 - 'active' => 'Active Documents', 22 - 'all' => 'All Documents', 23 - 'updates' => 'Recently Updated', 21 + 'active' => pht('Active Documents'), 22 + 'all' => pht('All Documents'), 23 + 'updates' => pht('Recently Updated'), 24 24 ); 25 25 26 26 if (empty($views[$this->view])) { 27 27 $this->view = 'active'; 28 28 } 29 29 30 - $nav = new AphrontSideNavFilterView(); 31 - $nav->setBaseURI(new PhutilURI('/phriction/list/')); 32 - foreach ($views as $view => $name) { 33 - $nav->addFilter($view, $name); 34 - } 35 - $nav->selectFilter($this->view, null); 30 + $nav = $this->buildSideNavView($this->view); 31 + 32 + $header = id(new PhabricatorHeaderView()) 33 + ->setHeader($views[$this->view]); 34 + 35 + $nav->appendChild( 36 + array( 37 + $header, 38 + )); 36 39 37 40 $pager = new AphrontPagerView(); 38 41 $pager->setURI($request->getRequestURI(), 'page'); ··· 44 47 $phids = mpull($content, 'getAuthorPHID'); 45 48 46 49 $handles = $this->loadViewerHandles($phids); 47 - 48 50 49 51 $rows = array(); 50 52 foreach ($documents as $document) { ··· 79 81 'right', 80 82 )); 81 83 82 - $view_headers = array( 83 - 'active' => 'Active Documents', 84 - 'all' => 'All Documents', 85 - 'updates' => 'Recently Updated Documents', 86 - ); 87 - $view_header = $view_headers[$this->view]; 84 + $view_header = $views[$this->view]; 88 85 89 86 $panel = new AphrontPanelView(); 90 - $panel->setHeader($view_header); 91 87 $panel->appendChild($document_table); 92 88 $panel->appendChild($pager); 93 89 94 90 $nav->appendChild($panel); 95 91 96 - return $this->buildStandardPageResponse($nav, 97 - array( 98 - 'title' => 'Phriction Main' 99 - )); 92 + return $this->buildApplicationPage( 93 + $nav, 94 + array( 95 + 'title' => pht('Phriction Main'), 96 + )); 100 97 } 101 98 102 99 private function loadDocuments(AphrontPagerView $pager) {
+17 -1
src/applications/phriction/storage/PhrictionDocument.php
··· 3 3 /** 4 4 * @group phriction 5 5 */ 6 - final class PhrictionDocument extends PhrictionDAO { 6 + final class PhrictionDocument extends PhrictionDAO 7 + implements PhabricatorPolicyInterface { 7 8 8 9 protected $id; 9 10 protected $phid; ··· 83 84 return $parts[1].'/'; 84 85 } 85 86 87 + // TODO: Customize this? Copypasta from PhabricatorPaste. 88 + public function getCapabilities() { 89 + return array( 90 + PhabricatorPolicyCapability::CAN_VIEW, 91 + PhabricatorPolicyCapability::CAN_EDIT, 92 + ); 93 + } 94 + 95 + public function getPolicy($capability) { 96 + return PhabricatorPolicies::POLICY_USER; 97 + } 98 + 99 + public function hasAutomaticCapability($capability, PhabricatorUser $user) { 100 + return false; 101 + } 86 102 }