From 29114bea5f7eb97d610dc5f61f41975e7364c3af Mon Sep 17 00:00:00 2001 From: epriestley Date: Sat, 4 Feb 2017 07:08:49 -0800 Subject: [PATCH 01/48] Fix a policy error for restricted applications in a profile menu Ref T12174. This could improperly raise a policy error. Instead, hide the menu item. Auditors: chad --- .../menuitem/PhabricatorApplicationProfileMenuItem.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/applications/search/menuitem/PhabricatorApplicationProfileMenuItem.php b/src/applications/search/menuitem/PhabricatorApplicationProfileMenuItem.php index 92477522ba..aa42d56cfb 100644 --- a/src/applications/search/menuitem/PhabricatorApplicationProfileMenuItem.php +++ b/src/applications/search/menuitem/PhabricatorApplicationProfileMenuItem.php @@ -60,12 +60,12 @@ final class PhabricatorApplicationProfileMenuItem $viewer = $this->getViewer(); $phid = $config->getMenuItemProperty('application'); - $app = id(new PhabricatorApplicationQuery()) + $apps = id(new PhabricatorApplicationQuery()) ->setViewer($viewer) ->withPHIDs(array($phid)) - ->executeOne(); + ->execute(); - return $app; + return head($apps); } protected function newNavigationMenuItems( From 2c691ef009999ed5493971dbc29545cc805e1fe9 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Sat, 4 Feb 2017 09:41:03 -0800 Subject: [PATCH 02/48] Add more color/CSS to phui-icon-selector Summary: Fixes T12205. These got over-ridden at a global scale (correctly) and need to adjust local scopes better. Also make it more bluer. Test Plan: Go to Edit Dashboard, and pick a new icon for a Dashboard. Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Maniphest Tasks: T12205 Differential Revision: https://secure.phabricator.com/D17312 --- resources/celerity/map.php | 4 ++-- .../rsrc/css/phui/phui-icon-set-selector.css | 21 +++++++++++++++---- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/resources/celerity/map.php b/resources/celerity/map.php index 7bf3396ca8..750c4b0be4 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -151,7 +151,7 @@ return array( 'rsrc/css/phui/phui-head-thing.css' => 'fd311e5f', 'rsrc/css/phui/phui-header-view.css' => '92935c02', 'rsrc/css/phui/phui-hovercard.css' => 'e904f5dc', - 'rsrc/css/phui/phui-icon-set-selector.css' => '1ab67aad', + 'rsrc/css/phui/phui-icon-set-selector.css' => '87db8fee', 'rsrc/css/phui/phui-icon.css' => '09f46dd9', 'rsrc/css/phui/phui-image-mask.css' => 'a8498f9c', 'rsrc/css/phui/phui-info-panel.css' => '27ea50a1', @@ -864,7 +864,7 @@ return array( 'phui-header-view-css' => '92935c02', 'phui-hovercard' => '1bd28176', 'phui-hovercard-view-css' => 'e904f5dc', - 'phui-icon-set-selector-css' => '1ab67aad', + 'phui-icon-set-selector-css' => '87db8fee', 'phui-icon-view-css' => '09f46dd9', 'phui-image-mask-css' => 'a8498f9c', 'phui-info-panel-css' => '27ea50a1', diff --git a/webroot/rsrc/css/phui/phui-icon-set-selector.css b/webroot/rsrc/css/phui/phui-icon-set-selector.css index 09a0362246..c66c2a6e55 100644 --- a/webroot/rsrc/css/phui/phui-icon-set-selector.css +++ b/webroot/rsrc/css/phui/phui-icon-set-selector.css @@ -3,8 +3,10 @@ */ button.icon-button { - background: #f7f7f7; - border: 1px solid {$lightblueborder}; + background-color: #F7F7F9; + background-image: linear-gradient(to bottom, #ffffff, #f1f0f1); + border: 1px solid rgba({$alphablue},.2); + color: {$darkgreytext}; position: relative; width: 16px; height: 16px; @@ -15,6 +17,14 @@ button.icon-button { box-sizing: content-box; } +button.icon-button:hover { + border: 1px solid rgba({$alphablue},.5); +} + +button.icon-button .phui-icon-view { + color: {$darkbluetext}; +} + .icon-grid { text-align: center; } @@ -24,6 +34,9 @@ button.icon-button { } button.icon-button.selected { - background: {$bluebackground}; - border: 1px solid {$blueborder}; + border: 1px solid {$sky}; +} + +button.icon-button.selected .phui-icon-view { + color: {$sky}; } From d2c4d7d961b95c9d51a22ba0366f5d97c7850b41 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Sat, 4 Feb 2017 11:04:42 -0800 Subject: [PATCH 03/48] Clarify linking to comments in Remarkup Guide Summary: Provides additional hint on where to find and clarification. Test Plan: read Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Differential Revision: https://secure.phabricator.com/D17313 --- src/docs/user/userguide/remarkup.diviner | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/docs/user/userguide/remarkup.diviner b/src/docs/user/userguide/remarkup.diviner index 24e66c087d..6002867b78 100644 --- a/src/docs/user/userguide/remarkup.diviner +++ b/src/docs/user/userguide/remarkup.diviner @@ -361,9 +361,10 @@ commits and Maniphest tasks, by mentioning the name of an object: # You must specify at least 7 characters of the hash. T123 # Link to Maniphest task T123 -You can also link directly to a comment in Maniphest and Differential: +You can also link directly to a comment in Maniphest and Differential (these +can be found on the date stamp of any transaction/comment): - T123#4 # Link to comment #4 of T123 + T123#412 # Link to comment id #412 of task T123 See the Phabricator configuraton setting `remarkup.ignored-object-names` to modify this behavior. From f64edb993f6807fff1fdd854304c919e71ee4451 Mon Sep 17 00:00:00 2001 From: epriestley Date: Sat, 4 Feb 2017 16:06:57 -0800 Subject: [PATCH 04/48] Allow users who can edit a dashboard to remove invalid / restricted panels Summary: Ref T12207. Currently, to remove a panel from a dashboard, it must be a valid panel which you can see. Instead, only require that the panel PHID actually be listed somewhere in the dashboard's internal list of panels. This interacts with the "multiple instances of a panel" issue described in some more depth in T12207. In particular: - Currently, you can sort of add multiple copies of a panel to a dashboard, sometimes? Maybe? - This leads to great tragedy. This doesn't fix up the workflow with respect to multiple copies of a panel. We still remove by panel PHID (not by column/position or internal ID) so if a dashboard has multiple copies of the same panel for some reason, I think this workflow removes one of them arbitrarily (at best) or perhaps does something worse. I'm just treating this behavior as undefined for the moment. Test Plan: - Removed an invalid/hidden panel from a dashboard as a user with permission to edit that dashboard. - Tried to remove a made-up panel with a totally bogus PHID, got 404'd. - Viewed a dashboard with a restricted panel. - Put a hidden panel inside a tab panel, viewed it as a user who could not see it and a user who could. Reviewers: chad Reviewed By: chad Subscribers: swisspol Maniphest Tasks: T12207 Differential Revision: https://secure.phabricator.com/D17314 --- ...bricatorDashboardPanelRenderController.php | 1 + ...habricatorDashboardPanelViewController.php | 1 + ...bricatorDashboardRemovePanelController.php | 29 ++++++++--- ...abricatorDashboardPanelRenderingEngine.php | 52 +++++++++++++------ .../PhabricatorDashboardRenderingEngine.php | 1 + .../PhabricatorDashboardTabsPanelType.php | 1 + .../PhabricatorDashboardRemarkupRule.php | 1 + 7 files changed, 61 insertions(+), 25 deletions(-) diff --git a/src/applications/dashboard/controller/PhabricatorDashboardPanelRenderController.php b/src/applications/dashboard/controller/PhabricatorDashboardPanelRenderController.php index 0a0e7e30c0..8f25a0f9bb 100644 --- a/src/applications/dashboard/controller/PhabricatorDashboardPanelRenderController.php +++ b/src/applications/dashboard/controller/PhabricatorDashboardPanelRenderController.php @@ -34,6 +34,7 @@ final class PhabricatorDashboardPanelRenderController $rendered_panel = id(new PhabricatorDashboardPanelRenderingEngine()) ->setViewer($viewer) ->setPanel($panel) + ->setPanelPHID($panel->getPHID()) ->setParentPanelPHIDs($parent_phids) ->setHeaderMode($request->getStr('headerMode')) ->setDashboardID($request->getInt('dashboardID')) diff --git a/src/applications/dashboard/controller/PhabricatorDashboardPanelViewController.php b/src/applications/dashboard/controller/PhabricatorDashboardPanelViewController.php index 9fd9e1840d..4b5f1b45be 100644 --- a/src/applications/dashboard/controller/PhabricatorDashboardPanelViewController.php +++ b/src/applications/dashboard/controller/PhabricatorDashboardPanelViewController.php @@ -38,6 +38,7 @@ final class PhabricatorDashboardPanelViewController $rendered_panel = id(new PhabricatorDashboardPanelRenderingEngine()) ->setViewer($viewer) ->setPanel($panel) + ->setPanelPHID($panel->getPHID()) ->setParentPanelPHIDs(array()) ->renderPanel(); diff --git a/src/applications/dashboard/controller/PhabricatorDashboardRemovePanelController.php b/src/applications/dashboard/controller/PhabricatorDashboardRemovePanelController.php index 2fa8e83a10..c30b06c596 100644 --- a/src/applications/dashboard/controller/PhabricatorDashboardRemovePanelController.php +++ b/src/applications/dashboard/controller/PhabricatorDashboardRemovePanelController.php @@ -20,12 +20,25 @@ final class PhabricatorDashboardRemovePanelController return new Aphront404Response(); } + // NOTE: If you can edit a dashboard, you can remove panels from it even + // if you don't have permission to see them or they aren't valid. We only + // require that the panel be present on the dashboard. + $v_panel = $request->getStr('panelPHID'); - $panel = id(new PhabricatorDashboardPanelQuery()) - ->setViewer($viewer) - ->withPHIDs(array($v_panel)) - ->executeOne(); - if (!$panel) { + + $panel_on_dashboard = false; + $layout = $dashboard->getLayoutConfigObject(); + $columns = $layout->getPanelLocations(); + foreach ($columns as $column) { + foreach ($column as $column_panel_phid) { + if ($column_panel_phid == $v_panel) { + $panel_on_dashboard = true; + break; + } + } + } + + if (!$panel_on_dashboard) { return new Aphront404Response(); } @@ -43,11 +56,11 @@ final class PhabricatorDashboardRemovePanelController ->setNewValue( array( '-' => array( - $panel->getPHID() => $panel->getPHID(), + $v_panel => $v_panel, ), )); - $layout_config->removePanel($panel->getPHID()); + $layout_config->removePanel($v_panel); $dashboard->setLayoutConfigFromObject($layout_config); $editor = id(new PhabricatorDashboardTransactionEditor()) @@ -67,7 +80,7 @@ final class PhabricatorDashboardRemovePanelController ->appendChild(pht('Are you sure you want to remove this panel?')); return $this->newDialog() - ->setTitle(pht('Remove Panel %s', $panel->getMonogram())) + ->setTitle(pht('Remove Panel')) ->appendChild($form->buildLayoutView()) ->addCancelButton($redirect_uri) ->addSubmitButton(pht('Remove Panel')); diff --git a/src/applications/dashboard/engine/PhabricatorDashboardPanelRenderingEngine.php b/src/applications/dashboard/engine/PhabricatorDashboardPanelRenderingEngine.php index 286d749a18..fbd5aaa2bb 100644 --- a/src/applications/dashboard/engine/PhabricatorDashboardPanelRenderingEngine.php +++ b/src/applications/dashboard/engine/PhabricatorDashboardPanelRenderingEngine.php @@ -7,6 +7,7 @@ final class PhabricatorDashboardPanelRenderingEngine extends Phobject { const HEADER_MODE_EDIT = 'edit'; private $panel; + private $panelPHID; private $viewer; private $enableAsyncRendering; private $parentPanelPHIDs; @@ -66,6 +67,15 @@ final class PhabricatorDashboardPanelRenderingEngine extends Phobject { return $this->panel; } + public function setPanelPHID($panel_phid) { + $this->panelPHID = $panel_phid; + return $this; + } + + public function getPanelPHID() { + return $this->panelPHID; + } + public function renderPanel() { $panel = $this->getPanel(); $viewer = $this->getViewer(); @@ -255,32 +265,40 @@ final class PhabricatorDashboardPanelRenderingEngine extends Phobject { PHUIHeaderView $header) { $panel = $this->getPanel(); - if (!$panel) { - return $header; - } - $dashboard_id = $this->getDashboardID(); - $edit_uri = id(new PhutilURI( - '/dashboard/panel/edit/'.$panel->getID().'/')); - if ($dashboard_id) { - $edit_uri->setQueryParam('dashboardID', $dashboard_id); + + if ($panel) { + $panel_id = $panel->getID(); + + $edit_uri = "/dashboard/panel/edit/{$panel_id}/"; + $edit_uri = new PhutilURI($edit_uri); + if ($dashboard_id) { + $edit_uri->setQueryParam('dashboardID', $dashboard_id); + } + + $action_edit = id(new PHUIIconView()) + ->setIcon('fa-pencil') + ->setWorkflow(true) + ->setHref((string)$edit_uri); + + $header->addActionItem($action_edit); } - $action_edit = id(new PHUIIconView()) - ->setIcon('fa-pencil') - ->setWorkflow(true) - ->setHref((string)$edit_uri); - $header->addActionItem($action_edit); if ($dashboard_id) { - $uri = id(new PhutilURI( - '/dashboard/removepanel/'.$dashboard_id.'/')) - ->setQueryParam('panelPHID', $panel->getPHID()); + $panel_phid = $this->getPanelPHID(); + + $remove_uri = "/dashboard/removepanel/{$dashboard_id}/"; + $remove_uri = id(new PhutilURI($remove_uri)) + ->setQueryParam('panelPHID', $panel_phid); + $action_remove = id(new PHUIIconView()) ->setIcon('fa-trash-o') - ->setHref((string)$uri) + ->setHref((string)$remove_uri) ->setWorkflow(true); + $header->addActionItem($action_remove); } + return $header; } diff --git a/src/applications/dashboard/engine/PhabricatorDashboardRenderingEngine.php b/src/applications/dashboard/engine/PhabricatorDashboardRenderingEngine.php index f9af84973e..d1e1d3111c 100644 --- a/src/applications/dashboard/engine/PhabricatorDashboardRenderingEngine.php +++ b/src/applications/dashboard/engine/PhabricatorDashboardRenderingEngine.php @@ -55,6 +55,7 @@ final class PhabricatorDashboardRenderingEngine extends Phobject { ->setViewer($viewer) ->setDashboardID($dashboard->getID()) ->setEnableAsyncRendering(true) + ->setPanelPHID($panel_phid) ->setParentPanelPHIDs(array()) ->setHeaderMode($h_mode); diff --git a/src/applications/dashboard/paneltype/PhabricatorDashboardTabsPanelType.php b/src/applications/dashboard/paneltype/PhabricatorDashboardTabsPanelType.php index 4a0dae02f1..3cb758a11a 100644 --- a/src/applications/dashboard/paneltype/PhabricatorDashboardTabsPanelType.php +++ b/src/applications/dashboard/paneltype/PhabricatorDashboardTabsPanelType.php @@ -91,6 +91,7 @@ final class PhabricatorDashboardTabsPanelType ->setEnableAsyncRendering(true) ->setParentPanelPHIDs($parent_phids) ->setPanel($panel) + ->setPanelPHID($panel->getPHID()) ->setHeaderMode($no_headers) ->renderPanel(); } else { diff --git a/src/applications/dashboard/remarkup/PhabricatorDashboardRemarkupRule.php b/src/applications/dashboard/remarkup/PhabricatorDashboardRemarkupRule.php index 6b0a48dc01..d96852b10e 100644 --- a/src/applications/dashboard/remarkup/PhabricatorDashboardRemarkupRule.php +++ b/src/applications/dashboard/remarkup/PhabricatorDashboardRemarkupRule.php @@ -32,6 +32,7 @@ final class PhabricatorDashboardRemarkupRule return id(new PhabricatorDashboardPanelRenderingEngine()) ->setViewer($viewer) ->setPanel($object) + ->setPanelPHID($object->getPHID()) ->setParentPanelPHIDs($parent_phids) ->renderPanel(); From 70135d0ca80f949c0ae9743aed67afa0c39fd164 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Sun, 5 Feb 2017 20:45:27 +0000 Subject: [PATCH 05/48] Lots of little minor CSS tweaks Summary: Lots of little details, fix workboard bg colors, darken up global backgrounds just a hair, add more "widgety" look to dashboard panels, remove underline on anchors on mobile. Also Fixes T12210 Test Plan: Use lots of pages on mobile and desktop. Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Maniphest Tasks: T12210 Differential Revision: https://secure.phabricator.com/D17315 --- resources/celerity/map.php | 58 +++++++++---------- .../CelerityDefaultPostprocessor.php | 4 +- .../PhabricatorProjectBoardViewController.php | 4 +- .../css/application/dashboard/dashboard.css | 21 +++++++ .../people/people-picture-menu-item.css | 7 +-- webroot/rsrc/css/core/core.css | 2 +- .../phui/object-item/phui-oi-list-view.css | 2 +- webroot/rsrc/css/phui/phui-action-list.css | 4 ++ .../phui/workboards/phui-workboard-color.css | 4 ++ 9 files changed, 68 insertions(+), 38 deletions(-) diff --git a/resources/celerity/map.php b/resources/celerity/map.php index 750c4b0be4..5d79b0636c 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -7,9 +7,9 @@ */ return array( 'names' => array( - 'conpherence.pkg.css' => 'e25569a9', + 'conpherence.pkg.css' => 'a520d619', 'conpherence.pkg.js' => '6249a1cf', - 'core.pkg.css' => '867a3ad4', + 'core.pkg.css' => '946cfd80', 'core.pkg.js' => '1fa7c0c5', 'darkconsole.pkg.js' => 'e7393ebb', 'differential.pkg.css' => '4815647b', @@ -34,7 +34,7 @@ return array( 'rsrc/css/aphront/typeahead.css' => 'd4f16145', 'rsrc/css/application/almanac/almanac.css' => 'dbb9b3af', 'rsrc/css/application/auth/auth.css' => '0877ed6e', - 'rsrc/css/application/base/main-menu-view.css' => '62c04564', + 'rsrc/css/application/base/main-menu-view.css' => '43d59288', 'rsrc/css/application/base/notification-menu.css' => '6a697e43', 'rsrc/css/application/base/phui-theme.css' => '9f261c6b', 'rsrc/css/application/base/standard-page-view.css' => '894d8a25', @@ -47,15 +47,15 @@ return array( 'rsrc/css/application/config/unhandled-exception.css' => '4c96257a', 'rsrc/css/application/conpherence/durable-column.css' => 'd82e130c', 'rsrc/css/application/conpherence/header-pane.css' => 'db93ebc6', - 'rsrc/css/application/conpherence/menu.css' => '4f51db5a', + 'rsrc/css/application/conpherence/menu.css' => '3d8e5c9c', 'rsrc/css/application/conpherence/message-pane.css' => 'b085d40d', 'rsrc/css/application/conpherence/notification.css' => '965db05b', - 'rsrc/css/application/conpherence/participant-pane.css' => 'ac1baaa8', + 'rsrc/css/application/conpherence/participant-pane.css' => '604a8b02', 'rsrc/css/application/conpherence/transaction.css' => '85129c68', 'rsrc/css/application/contentsource/content-source-view.css' => '4b8b05d4', 'rsrc/css/application/countdown/timer.css' => '16c52f5c', 'rsrc/css/application/daemon/bulk-job.css' => 'df9c1d4a', - 'rsrc/css/application/dashboard/dashboard.css' => 'bc6f2127', + 'rsrc/css/application/dashboard/dashboard.css' => 'b1879090', 'rsrc/css/application/diff/inline-comment-summary.css' => '51efda3a', 'rsrc/css/application/differential/add-comment.css' => 'c47f8c40', 'rsrc/css/application/differential/changeset-view.css' => '6a9bdf9c', @@ -81,7 +81,7 @@ return array( 'rsrc/css/application/objectselector/object-selector.css' => '85ee8ce6', 'rsrc/css/application/owners/owners-path-editor.css' => '2f00933b', 'rsrc/css/application/paste/paste.css' => '1898e534', - 'rsrc/css/application/people/people-picture-menu-item.css' => '1ac65ef7', + 'rsrc/css/application/people/people-picture-menu-item.css' => 'a06f7f34', 'rsrc/css/application/people/people-profile.css' => '2473d929', 'rsrc/css/application/phame/phame.css' => '53fa6236', 'rsrc/css/application/pholio/pholio-edit.css' => '07676f51', @@ -107,7 +107,7 @@ return array( 'rsrc/css/application/slowvote/slowvote.css' => 'a94b7230', 'rsrc/css/application/tokens/tokens.css' => '3d0f239e', 'rsrc/css/application/uiexample/example.css' => '528b19de', - 'rsrc/css/core/core.css' => '50dd5fa6', + 'rsrc/css/core/core.css' => '9f4cb463', 'rsrc/css/core/remarkup.css' => '4a2de2bb', 'rsrc/css/core/syntax.css' => '769d3498', 'rsrc/css/core/z-index.css' => '5e72c4e0', @@ -126,20 +126,20 @@ return array( 'rsrc/css/phui/object-item/phui-oi-color.css' => 'cd2b9b77', 'rsrc/css/phui/object-item/phui-oi-drag-ui.css' => 'f12cbc9f', 'rsrc/css/phui/object-item/phui-oi-flush-ui.css' => '9d9685d6', - 'rsrc/css/phui/object-item/phui-oi-list-view.css' => 'bff632a4', + 'rsrc/css/phui/object-item/phui-oi-list-view.css' => '5c383524', 'rsrc/css/phui/object-item/phui-oi-simple-ui.css' => 'a8beebea', - 'rsrc/css/phui/phui-action-list.css' => '5679229f', + 'rsrc/css/phui/phui-action-list.css' => '445c267b', 'rsrc/css/phui/phui-action-panel.css' => '91c7b835', 'rsrc/css/phui/phui-badge.css' => '3baef8db', - 'rsrc/css/phui/phui-basic-nav-view.css' => '3d4b207b', + 'rsrc/css/phui/phui-basic-nav-view.css' => 'c2707bf1', 'rsrc/css/phui/phui-big-info-view.css' => 'bd903741', 'rsrc/css/phui/phui-box.css' => '269cbc99', 'rsrc/css/phui/phui-button.css' => '7eaff361', 'rsrc/css/phui/phui-chart.css' => '6bf6f78e', - 'rsrc/css/phui/phui-cms.css' => 'be43c8a8', + 'rsrc/css/phui/phui-cms.css' => '504b4b23', 'rsrc/css/phui/phui-comment-form.css' => '48fbd65d', 'rsrc/css/phui/phui-comment-panel.css' => 'f50152ad', - 'rsrc/css/phui/phui-crumbs-view.css' => 'f82868f2', + 'rsrc/css/phui/phui-crumbs-view.css' => 'b743f73e', 'rsrc/css/phui/phui-curtain-view.css' => '947bf1a4', 'rsrc/css/phui/phui-document-pro.css' => 'f56738ed', 'rsrc/css/phui/phui-document-summary.css' => '9ca48bdf', @@ -170,7 +170,7 @@ return array( 'rsrc/css/phui/phui-tag-view.css' => '84d65f26', 'rsrc/css/phui/phui-timeline-view.css' => 'bc523970', 'rsrc/css/phui/phui-two-column-view.css' => '8a1074c7', - 'rsrc/css/phui/workboards/phui-workboard-color.css' => 'f0551a33', + 'rsrc/css/phui/workboards/phui-workboard-color.css' => '783cdff5', 'rsrc/css/phui/workboards/phui-workboard.css' => '3bc85455', 'rsrc/css/phui/workboards/phui-workcard.css' => 'cca5fa92', 'rsrc/css/phui/workboards/phui-workpanel.css' => 'a3a63478', @@ -565,10 +565,10 @@ return array( 'config-page-css' => 'c1d5121b', 'conpherence-durable-column-view' => 'd82e130c', 'conpherence-header-pane-css' => 'db93ebc6', - 'conpherence-menu-css' => '4f51db5a', + 'conpherence-menu-css' => '3d8e5c9c', 'conpherence-message-pane-css' => 'b085d40d', 'conpherence-notification-css' => '965db05b', - 'conpherence-participant-pane-css' => 'ac1baaa8', + 'conpherence-participant-pane-css' => '604a8b02', 'conpherence-thread-manager' => 'c8b5ee6f', 'conpherence-transaction-css' => '85129c68', 'd3' => 'a11a5ff2', @@ -778,15 +778,15 @@ return array( 'owners-path-editor-css' => '2f00933b', 'paste-css' => '1898e534', 'path-typeahead' => 'f7fc67ec', - 'people-picture-menu-item-css' => '1ac65ef7', + 'people-picture-menu-item-css' => 'a06f7f34', 'people-profile-css' => '2473d929', - 'phabricator-action-list-view-css' => '5679229f', + 'phabricator-action-list-view-css' => '445c267b', 'phabricator-busy' => '59a7976a', 'phabricator-chatlog-css' => 'd295b020', 'phabricator-content-source-view-css' => '4b8b05d4', - 'phabricator-core-css' => '50dd5fa6', + 'phabricator-core-css' => '9f4cb463', 'phabricator-countdown-css' => '16c52f5c', - 'phabricator-dashboard-css' => 'bc6f2127', + 'phabricator-dashboard-css' => 'b1879090', 'phabricator-drag-and-drop-file-upload' => '58dea2fa', 'phabricator-draggable-list' => 'bea6e7f4', 'phabricator-fatal-config-template-css' => '8f18fa41', @@ -797,7 +797,7 @@ return array( 'phabricator-flag-css' => 'bba8f811', 'phabricator-keyboard-shortcut' => '1ae869f2', 'phabricator-keyboard-shortcut-manager' => '4a021c10', - 'phabricator-main-menu-view' => '62c04564', + 'phabricator-main-menu-view' => '43d59288', 'phabricator-nav-view-css' => 'b29426e9', 'phabricator-notification' => 'ccf1cbf8', 'phabricator-notification-css' => '3f6c89c9', @@ -838,7 +838,7 @@ return array( 'phriction-document-css' => '4282e4ad', 'phui-action-panel-css' => '91c7b835', 'phui-badge-view-css' => '3baef8db', - 'phui-basic-nav-view-css' => '3d4b207b', + 'phui-basic-nav-view-css' => 'c2707bf1', 'phui-big-info-view-css' => 'bd903741', 'phui-box-css' => '269cbc99', 'phui-button-css' => '7eaff361', @@ -847,10 +847,10 @@ return array( 'phui-calendar-list-css' => 'eb5c774b', 'phui-calendar-month-css' => '8e10e92c', 'phui-chart-css' => '6bf6f78e', - 'phui-cms-css' => 'be43c8a8', + 'phui-cms-css' => '504b4b23', 'phui-comment-form-css' => '48fbd65d', 'phui-comment-panel-css' => 'f50152ad', - 'phui-crumbs-view-css' => 'f82868f2', + 'phui-crumbs-view-css' => 'b743f73e', 'phui-curtain-view-css' => '947bf1a4', 'phui-document-summary-view-css' => '9ca48bdf', 'phui-document-view-css' => 'c32e8dec', @@ -878,7 +878,7 @@ return array( 'phui-oi-color-css' => 'cd2b9b77', 'phui-oi-drag-ui-css' => 'f12cbc9f', 'phui-oi-flush-ui-css' => '9d9685d6', - 'phui-oi-list-view-css' => 'bff632a4', + 'phui-oi-list-view-css' => '5c383524', 'phui-oi-simple-ui-css' => 'a8beebea', 'phui-pager-css' => 'bea33d23', 'phui-pinboard-view-css' => '2495140e', @@ -891,7 +891,7 @@ return array( 'phui-theme-css' => '9f261c6b', 'phui-timeline-view-css' => 'bc523970', 'phui-two-column-view-css' => '8a1074c7', - 'phui-workboard-color-css' => 'f0551a33', + 'phui-workboard-color-css' => '783cdff5', 'phui-workboard-view-css' => '3bc85455', 'phui-workcard-view-css' => 'cca5fa92', 'phui-workpanel-view-css' => 'a3a63478', @@ -1176,6 +1176,9 @@ return array( 'javelin-dom', 'javelin-request', ), + '43d59288' => array( + 'phui-theme-css', + ), '44959b73' => array( 'javelin-util', 'javelin-uri', @@ -1367,9 +1370,6 @@ return array( 'javelin-magical-init', 'javelin-util', ), - '62c04564' => array( - 'phui-theme-css', - ), '62dfea03' => array( 'javelin-install', 'javelin-util', diff --git a/src/applications/celerity/postprocessor/CelerityDefaultPostprocessor.php b/src/applications/celerity/postprocessor/CelerityDefaultPostprocessor.php index 1171266c0c..19a4a363e1 100644 --- a/src/applications/celerity/postprocessor/CelerityDefaultPostprocessor.php +++ b/src/applications/celerity/postprocessor/CelerityDefaultPostprocessor.php @@ -201,8 +201,8 @@ final class CelerityDefaultPostprocessor 'copy-background' => '#f1c40f', // Background color for "most" themes. - 'page.background' => '#f8f8fb', - 'page.sidenav' => '#f0f0f2', + 'page.background' => '#f3f5f7', + 'page.sidenav' => '#eaedf1', 'menu.profile.text' => 'rgba(255,255,255,.8)', 'menu.profile.text.selected' => 'rgba(255,255,255,1)', diff --git a/src/applications/project/controller/PhabricatorProjectBoardViewController.php b/src/applications/project/controller/PhabricatorProjectBoardViewController.php index fa2a423b09..7e682fb258 100644 --- a/src/applications/project/controller/PhabricatorProjectBoardViewController.php +++ b/src/applications/project/controller/PhabricatorProjectBoardViewController.php @@ -452,12 +452,14 @@ final class PhabricatorProjectBoardViewController )); $background = $project->getDisplayWorkboardBackgroundColor(); + require_celerity_resource('phui-workboard-color-css'); if ($background !== null) { - require_celerity_resource('phui-workboard-color-css'); $background_color_class = "phui-workboard-{$background}"; $page->addClass('phui-workboard-color'); $page->addClass($background_color_class); + } else { + $page->addClass('phui-workboard-no-color'); } return $page; diff --git a/webroot/rsrc/css/application/dashboard/dashboard.css b/webroot/rsrc/css/application/dashboard/dashboard.css index d8f4d3450e..a7ee4e1bbc 100644 --- a/webroot/rsrc/css/application/dashboard/dashboard.css +++ b/webroot/rsrc/css/application/dashboard/dashboard.css @@ -14,6 +14,27 @@ margin: 0 0 16px 0; } +.dashboard-view .phui-box-border { + border-color: rgba({$alphablue},.2); + border-bottom-color: rgba({$alphablue},.3); +} + +.dashboard-view .phui-header-shell { + padding-top: 4px; + padding-bottom: 16px; +} + +.dashboard-view .phui-header-header { + color: #000; +} + +.dashboard-view .phui-oi-empty .phui-info-view { + padding-top: 16px; + padding-bottom: 16px; + font-style: italic; + color: {$lightgreytext}; +} + .dashboard-view .phui-object-box .phui-object-box { margin: 0; } diff --git a/webroot/rsrc/css/application/people/people-picture-menu-item.css b/webroot/rsrc/css/application/people/people-picture-menu-item.css index 4f3d36fa9d..8f5da76166 100644 --- a/webroot/rsrc/css/application/people/people-picture-menu-item.css +++ b/webroot/rsrc/css/application/people/people-picture-menu-item.css @@ -5,14 +5,13 @@ .people-menu-image { width: 160px; height: 160px; - border: 1px solid {$thinblueborder}; } .people-menu-image-container { background: #fff; - padding: 4px; - border-radius: 3px; - border: 1px solid {$lightblueborder}; + padding: 5px; + border-radius: 5px; + border: 1px solid rgba({$alphablue},.2); margin: 4px 0px 16px 20px; display: inline-block; } diff --git a/webroot/rsrc/css/core/core.css b/webroot/rsrc/css/core/core.css index af6732260b..01c4414454 100644 --- a/webroot/rsrc/css/core/core.css +++ b/webroot/rsrc/css/core/core.css @@ -84,7 +84,7 @@ a { cursor: pointer; } -a:hover { +.device-desktop a:hover { text-decoration: underline; } diff --git a/webroot/rsrc/css/phui/object-item/phui-oi-list-view.css b/webroot/rsrc/css/phui/object-item/phui-oi-list-view.css index 018245e21c..b4cdbebe39 100644 --- a/webroot/rsrc/css/phui/object-item/phui-oi-list-view.css +++ b/webroot/rsrc/css/phui/object-item/phui-oi-list-view.css @@ -551,7 +551,7 @@ ul.phui-oi-list-view .phui-oi-selected color: {$darkbluetext}; border-top: 1px solid {$thinblueborder}; border-bottom: 1px solid {$thinblueborder}; - padding: 8px; + padding: 8px 12px; background-color: {$lightgreybackground}; } diff --git a/webroot/rsrc/css/phui/phui-action-list.css b/webroot/rsrc/css/phui/phui-action-list.css index 354d3fd6e7..0df93607f5 100644 --- a/webroot/rsrc/css/phui/phui-action-list.css +++ b/webroot/rsrc/css/phui/phui-action-list.css @@ -57,6 +57,10 @@ min-width: 0; } +.phabricator-action-view button.phabricator-action-view-item .phui-icon-view { + color: {$darkbluetext}; +} + .phabricator-action-view button.phabricator-action-view-item, .phabricator-action-view-item { padding: 4px 8px 6px 8px; diff --git a/webroot/rsrc/css/phui/workboards/phui-workboard-color.css b/webroot/rsrc/css/phui/workboards/phui-workboard-color.css index b16184e34b..e07bc6597f 100644 --- a/webroot/rsrc/css/phui/workboards/phui-workboard-color.css +++ b/webroot/rsrc/css/phui/workboards/phui-workboard-color.css @@ -6,6 +6,10 @@ background-color: transparent; } +.phui-workboard-no-color { + background-color: #fff; +} + .phui-workboard-color .phui-crumbs-view { background-color: rgba({$alphagrey},.15); border: none; From 3d44208e4f6559fb79e5dbd9fe7e8804b4d65865 Mon Sep 17 00:00:00 2001 From: epriestley Date: Mon, 6 Feb 2017 05:01:03 -0800 Subject: [PATCH 06/48] Clarify that "account.editable" no longer extends to profile pictures Summary: Fixes T12216. I'd like to remove this option eventually, but just narrow its scope in the config description for now. Test Plan: Read config description. Reviewers: chad Reviewed By: chad Maniphest Tasks: T12216 Differential Revision: https://secure.phabricator.com/D17317 --- .../PhabricatorAuthenticationConfigOptions.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/applications/config/option/PhabricatorAuthenticationConfigOptions.php b/src/applications/config/option/PhabricatorAuthenticationConfigOptions.php index bd1c8965eb..2239d98858 100644 --- a/src/applications/config/option/PhabricatorAuthenticationConfigOptions.php +++ b/src/applications/config/option/PhabricatorAuthenticationConfigOptions.php @@ -84,11 +84,13 @@ final class PhabricatorAuthenticationConfigOptions 'Determines whether or not basic account information is editable.')) ->setDescription( pht( - 'Is basic account information (email, real name, profile '. - 'picture) editable? If you set up Phabricator to automatically '. - 'synchronize account information from some other authoritative '. - 'system, you can disable this to ensure information remains '. - 'consistent across both systems.')), + 'This option controls whether users can edit account email '. + 'addresses and profile real names.'. + "\n\n". + 'If you set up Phabricator to automatically synchronize account '. + 'information from some other authoritative system, you can '. + 'prevent users from making these edits to ensure information '. + 'remains consistent across both systems.')), $this->newOption('account.minimum-password-length', 'int', 8) ->setSummary(pht('Minimum password length.')) ->setDescription( From 75abf799538f2dfcbaf97d5ad36959734c6da607 Mon Sep 17 00:00:00 2001 From: epriestley Date: Mon, 6 Feb 2017 04:26:43 -0800 Subject: [PATCH 07/48] Remove bad "Session" link in User activity logs Summary: Fixes T12215. Two issues: - We build this `$session` link out of `$ip`, which is (a) wrong even if `$ip` was the IP and (b) super wrong since `$ip` is a tag. - These links don't work even if we'd built them right: searching by the //prefix// of a session identifier does nothing. At least for now, just get rid of the links rather than trying to make this behavior work. Test Plan: On People > Activity logs: - Before patch: Saw bad links with bogus targets in "session" column. - After patch: Saw plain text in "session" column. Reviewers: chad Reviewed By: chad Maniphest Tasks: T12215 Differential Revision: https://secure.phabricator.com/D17316 --- src/applications/people/view/PhabricatorUserLogView.php | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/applications/people/view/PhabricatorUserLogView.php b/src/applications/people/view/PhabricatorUserLogView.php index c442cfd934..d648b248f7 100644 --- a/src/applications/people/view/PhabricatorUserLogView.php +++ b/src/applications/people/view/PhabricatorUserLogView.php @@ -43,12 +43,6 @@ final class PhabricatorUserLogView extends AphrontView { 'href' => $base_uri.'?ip='.$ip.'#R', ), $ip); - $session = phutil_tag( - 'a', - array( - 'href' => $base_uri.'?sessions='.$ip.'#R', - ), - $session); } $action = $log->getAction(); From b33bb3714bdb570d1e2a9b5b6fec4c5969f8b3af Mon Sep 17 00:00:00 2001 From: Chad Little Date: Mon, 6 Feb 2017 08:54:55 -0800 Subject: [PATCH 08/48] Add some max-width to basic-nav Summary: Fixes T12214. Adds a max-width Test Plan: Tested on Home, Projects, Appsearch Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Maniphest Tasks: T12214 Differential Revision: https://secure.phabricator.com/D17318 --- resources/celerity/map.php | 10 +++++----- webroot/rsrc/css/aphront/phabricator-nav-view.css | 1 + webroot/rsrc/css/phui/phui-basic-nav-view.css | 1 + 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/resources/celerity/map.php b/resources/celerity/map.php index 5d79b0636c..54d469272f 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -9,7 +9,7 @@ return array( 'names' => array( 'conpherence.pkg.css' => 'a520d619', 'conpherence.pkg.js' => '6249a1cf', - 'core.pkg.css' => '946cfd80', + 'core.pkg.css' => 'c50d8f46', 'core.pkg.js' => '1fa7c0c5', 'darkconsole.pkg.js' => 'e7393ebb', 'differential.pkg.css' => '4815647b', @@ -26,7 +26,7 @@ return array( 'rsrc/css/aphront/multi-column.css' => '84cc6640', 'rsrc/css/aphront/notification.css' => '3f6c89c9', 'rsrc/css/aphront/panel-view.css' => '8427b78d', - 'rsrc/css/aphront/phabricator-nav-view.css' => 'b29426e9', + 'rsrc/css/aphront/phabricator-nav-view.css' => 'e58a4a30', 'rsrc/css/aphront/table-view.css' => '213a5981', 'rsrc/css/aphront/tokenizer.css' => '9a8cb501', 'rsrc/css/aphront/tooltip.css' => '173b9431', @@ -131,7 +131,7 @@ return array( 'rsrc/css/phui/phui-action-list.css' => '445c267b', 'rsrc/css/phui/phui-action-panel.css' => '91c7b835', 'rsrc/css/phui/phui-badge.css' => '3baef8db', - 'rsrc/css/phui/phui-basic-nav-view.css' => 'c2707bf1', + 'rsrc/css/phui/phui-basic-nav-view.css' => '2e7648d4', 'rsrc/css/phui/phui-big-info-view.css' => 'bd903741', 'rsrc/css/phui/phui-box.css' => '269cbc99', 'rsrc/css/phui/phui-button.css' => '7eaff361', @@ -798,7 +798,7 @@ return array( 'phabricator-keyboard-shortcut' => '1ae869f2', 'phabricator-keyboard-shortcut-manager' => '4a021c10', 'phabricator-main-menu-view' => '43d59288', - 'phabricator-nav-view-css' => 'b29426e9', + 'phabricator-nav-view-css' => 'e58a4a30', 'phabricator-notification' => 'ccf1cbf8', 'phabricator-notification-css' => '3f6c89c9', 'phabricator-notification-menu-css' => '6a697e43', @@ -838,7 +838,7 @@ return array( 'phriction-document-css' => '4282e4ad', 'phui-action-panel-css' => '91c7b835', 'phui-badge-view-css' => '3baef8db', - 'phui-basic-nav-view-css' => 'c2707bf1', + 'phui-basic-nav-view-css' => '2e7648d4', 'phui-big-info-view-css' => 'bd903741', 'phui-box-css' => '269cbc99', 'phui-button-css' => '7eaff361', diff --git a/webroot/rsrc/css/aphront/phabricator-nav-view.css b/webroot/rsrc/css/aphront/phabricator-nav-view.css index 0846a1a4fe..a9c32f2e00 100644 --- a/webroot/rsrc/css/aphront/phabricator-nav-view.css +++ b/webroot/rsrc/css/aphront/phabricator-nav-view.css @@ -29,6 +29,7 @@ padding-right: 0; background-color: transparent; width: 205px; + max-width: 205px; } .device-phone .phui-basic-nav.phui-navigation-shell diff --git a/webroot/rsrc/css/phui/phui-basic-nav-view.css b/webroot/rsrc/css/phui/phui-basic-nav-view.css index 12605cc552..cabf146fde 100644 --- a/webroot/rsrc/css/phui/phui-basic-nav-view.css +++ b/webroot/rsrc/css/phui/phui-basic-nav-view.css @@ -40,6 +40,7 @@ .phui-basic-nav.phui-navigation-shell .phabricator-nav-local { width: 205px; + max-width: 205px; padding-top: 12px; padding-right: 8px; } From b58e18bad78525479388e13f017fe4ac1d94e221 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Mon, 6 Feb 2017 09:22:56 -0800 Subject: [PATCH 09/48] Allow action-list-items to also use text-overflow ellipsis Summary: These just cut off currently if the menu item name is too wide (like mobile). Add some ellipsis Test Plan: Check long name on mobile action list menu Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Differential Revision: https://secure.phabricator.com/D17319 --- resources/celerity/map.php | 6 +++--- webroot/rsrc/css/phui/phui-action-list.css | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/resources/celerity/map.php b/resources/celerity/map.php index 54d469272f..a3418a5069 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -9,7 +9,7 @@ return array( 'names' => array( 'conpherence.pkg.css' => 'a520d619', 'conpherence.pkg.js' => '6249a1cf', - 'core.pkg.css' => 'c50d8f46', + 'core.pkg.css' => '25475b75', 'core.pkg.js' => '1fa7c0c5', 'darkconsole.pkg.js' => 'e7393ebb', 'differential.pkg.css' => '4815647b', @@ -128,7 +128,7 @@ return array( 'rsrc/css/phui/object-item/phui-oi-flush-ui.css' => '9d9685d6', 'rsrc/css/phui/object-item/phui-oi-list-view.css' => '5c383524', 'rsrc/css/phui/object-item/phui-oi-simple-ui.css' => 'a8beebea', - 'rsrc/css/phui/phui-action-list.css' => '445c267b', + 'rsrc/css/phui/phui-action-list.css' => 'f980c059', 'rsrc/css/phui/phui-action-panel.css' => '91c7b835', 'rsrc/css/phui/phui-badge.css' => '3baef8db', 'rsrc/css/phui/phui-basic-nav-view.css' => '2e7648d4', @@ -780,7 +780,7 @@ return array( 'path-typeahead' => 'f7fc67ec', 'people-picture-menu-item-css' => 'a06f7f34', 'people-profile-css' => '2473d929', - 'phabricator-action-list-view-css' => '445c267b', + 'phabricator-action-list-view-css' => 'f980c059', 'phabricator-busy' => '59a7976a', 'phabricator-chatlog-css' => 'd295b020', 'phabricator-content-source-view-css' => '4b8b05d4', diff --git a/webroot/rsrc/css/phui/phui-action-list.css b/webroot/rsrc/css/phui/phui-action-list.css index 0df93607f5..874af5ee42 100644 --- a/webroot/rsrc/css/phui/phui-action-list.css +++ b/webroot/rsrc/css/phui/phui-action-list.css @@ -67,6 +67,8 @@ display: block; text-decoration: none; color: {$darkbluetext}; + text-overflow: ellipsis; + overflow: hidden; } .action-has-icon button.phabricator-action-view-item, From 1f4a89b613a6ca4f0be0c817fdce9a7862bf2b69 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Mon, 6 Feb 2017 10:50:09 -0800 Subject: [PATCH 10/48] More minor CSS tweaks globally Summary: Moves profile/project to use more standard colored boxes. Reverts dashboard border colors. Ensures better High-Contrast application more consistently across these projects. Also fix T12211. Test Plan: Home, People, Projects in High Contrast / Standard Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Maniphest Tasks: T12211 Differential Revision: https://secure.phabricator.com/D17321 --- resources/celerity/map.php | 22 +++++------ ...PhabricatorPeopleProfileViewController.php | 12 ++++-- .../PhabricatorProjectProfileController.php | 11 ++++-- .../css/application/dashboard/dashboard.css | 5 --- .../css/application/project/project-view.css | 37 +++++++------------ .../css/phui/calendar/phui-calendar-list.css | 2 +- webroot/rsrc/css/phui/phui-basic-nav-view.css | 4 -- webroot/rsrc/css/phui/phui-header-view.css | 4 ++ 8 files changed, 47 insertions(+), 50 deletions(-) diff --git a/resources/celerity/map.php b/resources/celerity/map.php index a3418a5069..e005d43a1b 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -9,7 +9,7 @@ return array( 'names' => array( 'conpherence.pkg.css' => 'a520d619', 'conpherence.pkg.js' => '6249a1cf', - 'core.pkg.css' => '25475b75', + 'core.pkg.css' => '72ab63ef', 'core.pkg.js' => '1fa7c0c5', 'darkconsole.pkg.js' => 'e7393ebb', 'differential.pkg.css' => '4815647b', @@ -55,7 +55,7 @@ return array( 'rsrc/css/application/contentsource/content-source-view.css' => '4b8b05d4', 'rsrc/css/application/countdown/timer.css' => '16c52f5c', 'rsrc/css/application/daemon/bulk-job.css' => 'df9c1d4a', - 'rsrc/css/application/dashboard/dashboard.css' => 'b1879090', + 'rsrc/css/application/dashboard/dashboard.css' => '226c4dc6', 'rsrc/css/application/diff/inline-comment-summary.css' => '51efda3a', 'rsrc/css/application/differential/add-comment.css' => 'c47f8c40', 'rsrc/css/application/differential/changeset-view.css' => '6a9bdf9c', @@ -97,7 +97,7 @@ return array( 'rsrc/css/application/policy/policy.css' => '957ea14c', 'rsrc/css/application/ponder/ponder-view.css' => 'fbd45f96', 'rsrc/css/application/project/project-card-view.css' => 'f25746f5', - 'rsrc/css/application/project/project-view.css' => 'ceabdbaa', + 'rsrc/css/application/project/project-view.css' => '9f6ce0e1', 'rsrc/css/application/releeph/releeph-core.css' => '9b3c5733', 'rsrc/css/application/releeph/releeph-preview-branch.css' => 'b7a6f4a5', 'rsrc/css/application/releeph/releeph-request-differential-create-dialog.css' => '8d8b92cd', @@ -119,7 +119,7 @@ return array( 'rsrc/css/layout/phabricator-filetree-view.css' => 'fccf9f82', 'rsrc/css/layout/phabricator-source-code-view.css' => '4383192f', 'rsrc/css/phui/calendar/phui-calendar-day.css' => '572b1893', - 'rsrc/css/phui/calendar/phui-calendar-list.css' => 'eb5c774b', + 'rsrc/css/phui/calendar/phui-calendar-list.css' => '576be600', 'rsrc/css/phui/calendar/phui-calendar-month.css' => '8e10e92c', 'rsrc/css/phui/calendar/phui-calendar.css' => '477acfaa', 'rsrc/css/phui/object-item/phui-oi-big-ui.css' => '19f9369b', @@ -131,7 +131,7 @@ return array( 'rsrc/css/phui/phui-action-list.css' => 'f980c059', 'rsrc/css/phui/phui-action-panel.css' => '91c7b835', 'rsrc/css/phui/phui-badge.css' => '3baef8db', - 'rsrc/css/phui/phui-basic-nav-view.css' => '2e7648d4', + 'rsrc/css/phui/phui-basic-nav-view.css' => 'a0705f53', 'rsrc/css/phui/phui-big-info-view.css' => 'bd903741', 'rsrc/css/phui/phui-box.css' => '269cbc99', 'rsrc/css/phui/phui-button.css' => '7eaff361', @@ -149,7 +149,7 @@ return array( 'rsrc/css/phui/phui-form-view.css' => 'adca31ce', 'rsrc/css/phui/phui-form.css' => '5815af7b', 'rsrc/css/phui/phui-head-thing.css' => 'fd311e5f', - 'rsrc/css/phui/phui-header-view.css' => '92935c02', + 'rsrc/css/phui/phui-header-view.css' => 'fef6a54e', 'rsrc/css/phui/phui-hovercard.css' => 'e904f5dc', 'rsrc/css/phui/phui-icon-set-selector.css' => '87db8fee', 'rsrc/css/phui/phui-icon.css' => '09f46dd9', @@ -786,7 +786,7 @@ return array( 'phabricator-content-source-view-css' => '4b8b05d4', 'phabricator-core-css' => '9f4cb463', 'phabricator-countdown-css' => '16c52f5c', - 'phabricator-dashboard-css' => 'b1879090', + 'phabricator-dashboard-css' => '226c4dc6', 'phabricator-drag-and-drop-file-upload' => '58dea2fa', 'phabricator-draggable-list' => 'bea6e7f4', 'phabricator-fatal-config-template-css' => '8f18fa41', @@ -838,13 +838,13 @@ return array( 'phriction-document-css' => '4282e4ad', 'phui-action-panel-css' => '91c7b835', 'phui-badge-view-css' => '3baef8db', - 'phui-basic-nav-view-css' => '2e7648d4', + 'phui-basic-nav-view-css' => 'a0705f53', 'phui-big-info-view-css' => 'bd903741', 'phui-box-css' => '269cbc99', 'phui-button-css' => '7eaff361', 'phui-calendar-css' => '477acfaa', 'phui-calendar-day-css' => '572b1893', - 'phui-calendar-list-css' => 'eb5c774b', + 'phui-calendar-list-css' => '576be600', 'phui-calendar-month-css' => '8e10e92c', 'phui-chart-css' => '6bf6f78e', 'phui-cms-css' => '504b4b23', @@ -861,7 +861,7 @@ return array( 'phui-form-css' => '5815af7b', 'phui-form-view-css' => 'adca31ce', 'phui-head-thing-view-css' => 'fd311e5f', - 'phui-header-view-css' => '92935c02', + 'phui-header-view-css' => 'fef6a54e', 'phui-hovercard' => '1bd28176', 'phui-hovercard-view-css' => 'e904f5dc', 'phui-icon-set-selector-css' => '87db8fee', @@ -906,7 +906,7 @@ return array( 'policy-transaction-detail-css' => '82100a43', 'ponder-view-css' => 'fbd45f96', 'project-card-view-css' => 'f25746f5', - 'project-view-css' => 'ceabdbaa', + 'project-view-css' => '9f6ce0e1', 'releeph-core' => '9b3c5733', 'releeph-preview-branch' => 'b7a6f4a5', 'releeph-request-differential-create-dialog' => '8d8b92cd', diff --git a/src/applications/people/controller/PhabricatorPeopleProfileViewController.php b/src/applications/people/controller/PhabricatorPeopleProfileViewController.php index 34a69c3bfb..889ecd2969 100644 --- a/src/applications/people/controller/PhabricatorPeopleProfileViewController.php +++ b/src/applications/people/controller/PhabricatorPeopleProfileViewController.php @@ -42,6 +42,7 @@ final class PhabricatorPeopleProfileViewController $home = id(new PHUITwoColumnView()) ->setHeader($header) ->addClass('project-view-home') + ->addClass('project-view-people-home') ->setMainColumn( array( $properties, @@ -87,8 +88,13 @@ final class PhabricatorPeopleProfileViewController return null; } + $header = id(new PHUIHeaderView()) + ->setHeader(pht('User Details')); + $view = id(new PHUIObjectBoxView()) ->appendChild($view) + ->setHeader($header) + ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) ->addClass('project-view-properties'); return $view; @@ -143,7 +149,7 @@ final class PhabricatorPeopleProfileViewController $box = id(new PHUIObjectBoxView()) ->setHeader($header) ->appendChild($list) - ->setBackground(PHUIObjectBoxView::GREY); + ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY); return $box; } @@ -217,7 +223,7 @@ final class PhabricatorPeopleProfileViewController ->setHeader($header) ->appendChild($day_view) ->addClass('calendar-profile-box') - ->setBackground(PHUIObjectBoxView::GREY); + ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY); return $box; } @@ -317,7 +323,7 @@ final class PhabricatorPeopleProfileViewController ->setHeader($header) ->addClass('project-view-badges') ->appendChild($flex) - ->setBackground(PHUIObjectBoxView::GREY); + ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY); return $box; } diff --git a/src/applications/project/controller/PhabricatorProjectProfileController.php b/src/applications/project/controller/PhabricatorProjectProfileController.php index ca9732b6f1..9e8d4edd49 100644 --- a/src/applications/project/controller/PhabricatorProjectProfileController.php +++ b/src/applications/project/controller/PhabricatorProjectProfileController.php @@ -59,14 +59,14 @@ final class PhabricatorProjectProfileController ->setUser($viewer) ->setProject($project) ->setLimit(5) - ->setBackground(PHUIObjectBoxView::GREY) + ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) ->setUserPHIDs($project->getMemberPHIDs()); $watcher_list = id(new PhabricatorProjectWatcherListView()) ->setUser($viewer) ->setProject($project) ->setLimit(5) - ->setBackground(PHUIObjectBoxView::GREY) + ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) ->setUserPHIDs($project->getWatcherPHIDs()); $nav = $this->getProfileMenu(); @@ -137,8 +137,13 @@ final class PhabricatorProjectProfileController return null; } + $header = id(new PHUIHeaderView()) + ->setHeader(pht('Properties')); + $view = id(new PHUIObjectBoxView()) + ->setHeader($header) ->appendChild($view) + ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) ->addClass('project-view-properties'); return $view; @@ -287,7 +292,7 @@ final class PhabricatorProjectProfileController return id(new PHUIObjectBoxView()) ->setHeader($header) - ->setBackground(PHUIObjectBoxView::GREY) + ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) ->setObjectList($subproject_list); } diff --git a/webroot/rsrc/css/application/dashboard/dashboard.css b/webroot/rsrc/css/application/dashboard/dashboard.css index a7ee4e1bbc..ace968a8eb 100644 --- a/webroot/rsrc/css/application/dashboard/dashboard.css +++ b/webroot/rsrc/css/application/dashboard/dashboard.css @@ -14,11 +14,6 @@ margin: 0 0 16px 0; } -.dashboard-view .phui-box-border { - border-color: rgba({$alphablue},.2); - border-bottom-color: rgba({$alphablue},.3); -} - .dashboard-view .phui-header-shell { padding-top: 4px; padding-bottom: 16px; diff --git a/webroot/rsrc/css/application/project/project-view.css b/webroot/rsrc/css/application/project/project-view.css index 9ba6a9f7e5..cc8d484426 100644 --- a/webroot/rsrc/css/application/project/project-view.css +++ b/webroot/rsrc/css/application/project/project-view.css @@ -2,6 +2,12 @@ * @provides project-view-css */ +.project-view-people-home.phui-two-column-view .phui-two-column-header { + background: transparent; + border: none; + margin-bottom: 8px; +} + .project-view-header-tag { margin-left: 8px; font-size: {$normalfontsize}; @@ -27,8 +33,6 @@ .project-view-home .phui-box.project-view-properties { margin: 0 0 16px 0; padding: 0; - border: 1px solid rgba({$alphagrey}, .2); - background-color: #fff; } .device-desktop .phui-two-column-view .project-view-properties @@ -38,7 +42,7 @@ .project-view-properties .phui-property-list-container + .phui-property-list-text-content { - border-color: rgba({$alphagrey},.2); + border-color: {$thinblueborder}; } .project-view-properties .phui-property-list-key { @@ -51,29 +55,16 @@ padding: 12px 4px 0; } -.project-view-feed.phui-object-box.phui-box-border { - border: 1px solid rgba({$alphagrey}, .2); -} - -.project-view-home .phui-box-grey { - padding: 0; -} - -.project-view-home .phui-box-grey .phui-header-shell { +.project-view-home .phui-side-column .phui-object-box .phui-header-shell { padding: 6px 6px 6px 12px; } -.project-view-home .phui-box-grey .phui-header-header { - font-size: {$biggerfontsize}; -} - -.project-view-home .phui-box-grey .phui-header-action-link { - margin-top: 0; - margin-bottom: 0; -} - -.project-view-home .phui-box-grey .phui-oi-list-view { - padding: 4px 8px 0 8px; +.project-view-home .phui-side-column .phui-object-box + div.phui-info-severity-nodata { + color: {$lightgreytext}; + font-style: italic; + border: none; + text-align: center; } .project-view-badges .phui-badge-flex-view { diff --git a/webroot/rsrc/css/phui/calendar/phui-calendar-list.css b/webroot/rsrc/css/phui/calendar/phui-calendar-list.css index f7d5e24683..c7b844a7eb 100644 --- a/webroot/rsrc/css/phui/calendar/phui-calendar-list.css +++ b/webroot/rsrc/css/phui/calendar/phui-calendar-list.css @@ -12,7 +12,7 @@ padding: 0 12px 12px; } -.project-view-home .phui-box-grey .phui-calendar-list-container +.project-view-home .phui-object-box .phui-calendar-list-container .phui-header-shell { padding: 8px 0; background: #fff; diff --git a/webroot/rsrc/css/phui/phui-basic-nav-view.css b/webroot/rsrc/css/phui/phui-basic-nav-view.css index cabf146fde..03b1deb917 100644 --- a/webroot/rsrc/css/phui/phui-basic-nav-view.css +++ b/webroot/rsrc/css/phui/phui-basic-nav-view.css @@ -27,10 +27,6 @@ display: none; } -.phabricator-home .phui-basic-nav .phabricator-side-menu { - background: transparent; -} - .device-phone.phabricator-home .phui-basic-nav .phabricator-side-menu .phui-list-item-selected { background-color: transparent; diff --git a/webroot/rsrc/css/phui/phui-header-view.css b/webroot/rsrc/css/phui/phui-header-view.css index 06d16f60b3..b47c93fe33 100644 --- a/webroot/rsrc/css/phui/phui-header-view.css +++ b/webroot/rsrc/css/phui/phui-header-view.css @@ -93,6 +93,10 @@ body .phui-header-shell.phui-bleed-header color: {$darkbluetext}; } +.phui-box-blue-property .phui-header-view .phui-header-header a { + color: {$bluetext}; +} + .device-desktop .phui-header-view .phui-header-header a:hover { text-decoration: none; color: {$blue}; From 638f2a012b2dbcc9c02b4bc4372d0f2459a8b2ef Mon Sep 17 00:00:00 2001 From: Chad Little Date: Tue, 7 Feb 2017 09:43:39 -0800 Subject: [PATCH 11/48] Add AuthorHref to feed story images Summary: Fixes T9336. Kind of a bit to back up and find the source, but works easily. Test Plan: View feed, click on my image. Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Maniphest Tasks: T9336 Differential Revision: https://secure.phabricator.com/D17322 --- .../feed/PhabricatorApplicationTransactionFeedStory.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/applications/transactions/feed/PhabricatorApplicationTransactionFeedStory.php b/src/applications/transactions/feed/PhabricatorApplicationTransactionFeedStory.php index 4e5c0e3ba1..6cc18d5181 100644 --- a/src/applications/transactions/feed/PhabricatorApplicationTransactionFeedStory.php +++ b/src/applications/transactions/feed/PhabricatorApplicationTransactionFeedStory.php @@ -105,6 +105,7 @@ class PhabricatorApplicationTransactionFeedStory if ($author_image) { $view->setImage($author_image); + $view->setImageHref($author_handle->getURI()); } else { $view->setAuthorIcon($author_handle->getIcon()); } From 3b558d7dd0e30275a8056c015503d48481b4b76e Mon Sep 17 00:00:00 2001 From: Chad Little Date: Wed, 8 Feb 2017 09:09:20 -0800 Subject: [PATCH 12/48] Add back the motivator panel Summary: Fixes T12226, Ref D17233. Resurrects the motivator panel. Test Plan: Add panel, see fact on hover. Reviewers: epriestley Reviewed By: epriestley Subscribers: yelirekim, jcox, Korvin Maniphest Tasks: T12226 Differential Revision: https://secure.phabricator.com/D17324 --- src/__phutil_library_map__.php | 2 + .../PhabricatorMotivatorProfileMenuItem.php | 160 ++++++++++++++++++ 2 files changed, 162 insertions(+) create mode 100644 src/applications/search/menuitem/PhabricatorMotivatorProfileMenuItem.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 033e7c15d2..5e38ba042e 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -3029,6 +3029,7 @@ phutil_register_library_map(array( 'PhabricatorModularTransactionType' => 'applications/transactions/storage/PhabricatorModularTransactionType.php', 'PhabricatorMonospacedFontSetting' => 'applications/settings/setting/PhabricatorMonospacedFontSetting.php', 'PhabricatorMonospacedTextareasSetting' => 'applications/settings/setting/PhabricatorMonospacedTextareasSetting.php', + 'PhabricatorMotivatorProfileMenuItem' => 'applications/search/menuitem/PhabricatorMotivatorProfileMenuItem.php', 'PhabricatorMultiColumnUIExample' => 'applications/uiexample/examples/PhabricatorMultiColumnUIExample.php', 'PhabricatorMultiFactorSettingsPanel' => 'applications/settings/panel/PhabricatorMultiFactorSettingsPanel.php', 'PhabricatorMultimeterApplication' => 'applications/multimeter/application/PhabricatorMultimeterApplication.php', @@ -8099,6 +8100,7 @@ phutil_register_library_map(array( 'PhabricatorModularTransactionType' => 'Phobject', 'PhabricatorMonospacedFontSetting' => 'PhabricatorStringSetting', 'PhabricatorMonospacedTextareasSetting' => 'PhabricatorSelectSetting', + 'PhabricatorMotivatorProfileMenuItem' => 'PhabricatorProfileMenuItem', 'PhabricatorMultiColumnUIExample' => 'PhabricatorUIExample', 'PhabricatorMultiFactorSettingsPanel' => 'PhabricatorSettingsPanel', 'PhabricatorMultimeterApplication' => 'PhabricatorApplication', diff --git a/src/applications/search/menuitem/PhabricatorMotivatorProfileMenuItem.php b/src/applications/search/menuitem/PhabricatorMotivatorProfileMenuItem.php new file mode 100644 index 0000000000..e67d22b555 --- /dev/null +++ b/src/applications/search/menuitem/PhabricatorMotivatorProfileMenuItem.php @@ -0,0 +1,160 @@ +getOptions(); + $name = idx($options, $config->getMenuItemProperty('source')); + if ($name !== null) { + return pht('Motivator: %s', $name); + } else { + return pht('Motivator'); + } + } + + public function buildEditEngineFields( + PhabricatorProfileMenuItemConfiguration $config) { + return array( + id(new PhabricatorInstructionsEditField()) + ->setValue( + pht( + 'Motivate your team with inspirational quotes from great minds. '. + 'This menu item shows a new quote every day.')), + id(new PhabricatorSelectEditField()) + ->setKey('source') + ->setLabel(pht('Source')) + ->setOptions($this->getOptions()), + ); + } + + private function getOptions() { + return array( + 'catfacts' => pht('Cat Facts'), + ); + } + + protected function newNavigationMenuItems( + PhabricatorProfileMenuItemConfiguration $config) { + + $source = $config->getMenuItemProperty('source'); + + switch ($source) { + case 'catfacts': + default: + $facts = $this->getCatFacts(); + $fact_name = pht('Cat Facts'); + $fact_icon = 'fa-paw'; + break; + } + + $fact_text = $this->selectFact($facts); + + $item = $this->newItem() + ->setName($fact_name) + ->setIcon($fact_icon) + ->setTooltip($fact_text) + ->setHref('#'); + + return array( + $item, + ); + } + + private function getCatFacts() { + return array( + pht('Cats purr when they are happy, upset, or asleep.'), + pht('The first cats evolved on the savanah about 8,000 years ago.'), + pht( + 'Cats have a tail, two feet, between one and three ears, and two '. + 'other feet.'), + pht('Cats use their keen sense of smell to avoid feeling empathy.'), + pht('The first cats evolved in swamps about 65 years ago.'), + pht( + 'You can tell how warm a cat is by examining the coloration: cooler '. + 'areas are darker.'), + pht( + 'Cat tails are flexible because they contain thousands of tiny '. + 'bones.'), + pht( + 'A cattail is a wetland plant with an appearance that resembles '. + 'the tail of a cat.'), + pht( + 'Cats must eat a diet rich in fish to replace the tiny bones in '. + 'their tails.'), + pht('Cats are stealthy predators and nearly invisible to radar.'), + pht( + 'Cats use a special type of magnetism to help them land on their '. + 'feet.'), + pht( + 'A cat can run seven times faster than a human, but only for a '. + 'short distance.'), + pht( + 'The largest recorded cat was nearly 11 inches long from nose to '. + 'tail.'), + pht( + 'Not all cats can retract their claws, but most of them can.'), + pht( + 'In the wild, cats and racoons sometimes hunt together in packs.'), + pht( + 'The Spanish word for cat is "cato". The biggest cat is called '. + '"el cato".'), + pht( + 'The Japanese word for cat is "kome", which is also the word for '. + 'rice. Japanese cats love to eat rice, so the two are synonymous.'), + pht('Cats have five pointy ends.'), + pht('cat -A can find mice hiding in files.'), + pht('A cat\'s visual, olfactory, and auditory senses, '. + 'Contribute to their hunting skills and natural defenses.'), + pht( + 'Cats with high self-esteem seek out high perches '. + 'to launch their attacks. Watch out!'), + pht('Cats prefer vanilla ice cream.'), + pht('Taco cat spelled backwards is taco cat.'), + pht( + 'Cats will often bring you their prey because they feel sorry '. + 'for your inability to hunt.'), + pht('Cats spend most of their time plotting to kill their owner.'), + pht('Outside of the CAT scan, cats have made almost no contributions '. + 'to modern medicine.'), + pht('In ancient Egypt, the cat-god Horus watched over all cats.'), + pht('The word "catastrophe" has no etymological relationship to the '. + 'word "cat".'), + pht('Many cats appear black in low light, suffering a -2 modifier to '. + 'luck rolls.'), + pht('The popular trivia game "World of Warcraft" features a race of '. + 'cat people called the Khajiit.'), + ); + } + + private function selectFact(array $facts) { + // This is a simple pseudorandom number generator that avoids touching + // srand(), because it would seed it to a highly predictable value. It + // selects a new fact every day. + + $seed = ((int)date('Y') * 366) + (int)date('z'); + for ($ii = 0; $ii < 32; $ii++) { + $seed = ((1664525 * $seed) + 1013904223) % (1 << 31); + } + + return $facts[$seed % count($facts)]; + } + + +} From 7d0d4708ca2e31e48fc0486e35ada563b837d788 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Thu, 9 Feb 2017 14:45:47 +0000 Subject: [PATCH 13/48] Fix icon color on project icon chooser Summary: These colors are also off from the icon change. Test Plan: Project -> Manage -> Edit Picture -> Choose Icon Reviewers: epriestley, 20after4 Reviewed By: epriestley Subscribers: Korvin Differential Revision: https://secure.phabricator.com/D17328 --- resources/celerity/map.php | 4 ++-- .../css/application/people/people-profile.css | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/resources/celerity/map.php b/resources/celerity/map.php index e005d43a1b..fcf5ff0f50 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -82,7 +82,7 @@ return array( 'rsrc/css/application/owners/owners-path-editor.css' => '2f00933b', 'rsrc/css/application/paste/paste.css' => '1898e534', 'rsrc/css/application/people/people-picture-menu-item.css' => 'a06f7f34', - 'rsrc/css/application/people/people-profile.css' => '2473d929', + 'rsrc/css/application/people/people-profile.css' => '4df76faf', 'rsrc/css/application/phame/phame.css' => '53fa6236', 'rsrc/css/application/pholio/pholio-edit.css' => '07676f51', 'rsrc/css/application/pholio/pholio-inline-comments.css' => '8e545e49', @@ -779,7 +779,7 @@ return array( 'paste-css' => '1898e534', 'path-typeahead' => 'f7fc67ec', 'people-picture-menu-item-css' => 'a06f7f34', - 'people-profile-css' => '2473d929', + 'people-profile-css' => '4df76faf', 'phabricator-action-list-view-css' => 'f980c059', 'phabricator-busy' => '59a7976a', 'phabricator-chatlog-css' => 'd295b020', diff --git a/webroot/rsrc/css/application/people/people-profile.css b/webroot/rsrc/css/application/people/people-profile.css index c5ec73551a..2fcb6daa20 100644 --- a/webroot/rsrc/css/application/people/people-profile.css +++ b/webroot/rsrc/css/application/people/people-profile.css @@ -15,7 +15,7 @@ button.profile-image-button { .compose-dialog button.profile-image-button-selected { background-image: none; background-color: {$lightblue}; - border-color: {$blueborder}; + border-color: {$sky}; } .compose-header { @@ -32,17 +32,17 @@ form.compose-dialog { .compose-dialog .phui-icon-view { display: block; position: relative; - width: 50px; - height: 50px; + width: 48px; + height: 48px; background-color: {$darkgreytext}; } -.compose-dialog .compose-icon-bg { - color: rgba({$alphawhite},0.8); - line-height: 50px; - width: 50px; +.compose-dialog .compose-icon-bg.phui-icon-view { + color: #e7e7e7; + line-height: 48px; + width: 48px; text-align: center; - font-size: 32px; + font-size: 28px; } .compose-dialog .compose-background-red { From 4997b6bd028de0034be7b3a4610d71eae83e6e35 Mon Sep 17 00:00:00 2001 From: epriestley Date: Thu, 9 Feb 2017 08:35:16 -0800 Subject: [PATCH 14/48] Never send normal mail to unverified addresses Summary: Ref T12237. This tightens our delivery rules, which previously sent normal mail to unverified addresses: - We sent general mail to unverified addresses so that you wouldn't miss anything between the time you sign up (or have an account created) and the time you verify your address. This was imagined as a slight convenience for users. - We sent automatic reply mail to unverified addresses if they sent mail to us first, saying "we don't recognize that address". This was imagined as a convenience for users who accidentally send mail "From" the wrong address (personal vs work, for example). I think both behaviors are probably a little better for users on the balance, but not having mail providers randomly shut us off without warning is better for me, personally -- so stop doing this stuff. This creates a problem which we likely need to solve before the release is cut: - On installs which do not require mail verification, mail to you will now mostly-silently be dropped if you never bothered to verify your address. I'd like to solve this by adding some kind of per-user alert that says "We recently tried to send you some mail but you haven't verified your address.", and giving them links to verify the address and review the mail. I'll pursue this after restoring mail service to `secure.phabricator.com`. Test Plan: - Added a unit test. - Unverified my address, sent mail, saw it get dropped. - Reverified my address, sent mail, saw it go through. - Verified that important mail (password reset, invite, confirm-this-address) either uses "Force Delivery" (skips this check) or "Raw To Addresses" (also skips this check). - Verified that Phacility instance stuff is also covered: it uses the same invite flow. Reviewers: chad Reviewed By: chad Maniphest Tasks: T12237 Differential Revision: https://secure.phabricator.com/D17329 --- .../metamta/query/PhabricatorMetaMTAActor.php | 14 ++++++++++++++ .../query/PhabricatorMetaMTAActorQuery.php | 8 ++++++++ .../metamta/receiver/PhabricatorMailReceiver.php | 16 ++++++++++------ .../metamta/storage/PhabricatorMetaMTAMail.php | 10 ++++++++++ .../__tests__/PhabricatorMetaMTAMailTestCase.php | 16 ++++++++++++++++ 5 files changed, 58 insertions(+), 6 deletions(-) diff --git a/src/applications/metamta/query/PhabricatorMetaMTAActor.php b/src/applications/metamta/query/PhabricatorMetaMTAActor.php index a15a5b2390..1f4cc7da12 100644 --- a/src/applications/metamta/query/PhabricatorMetaMTAActor.php +++ b/src/applications/metamta/query/PhabricatorMetaMTAActor.php @@ -20,12 +20,14 @@ final class PhabricatorMetaMTAActor extends Phobject { const REASON_FORCE_HERALD = 'force-herald'; const REASON_ROUTE_AS_NOTIFICATION = 'route-as-notification'; const REASON_ROUTE_AS_MAIL = 'route-as-mail'; + const REASON_UNVERIFIED = 'unverified'; private $phid; private $emailAddress; private $name; private $status = self::STATUS_DELIVERABLE; private $reasons = array(); + private $isVerified = false; public function setName($name) { $this->name = $name; @@ -45,6 +47,15 @@ final class PhabricatorMetaMTAActor extends Phobject { return $this->emailAddress; } + public function setIsVerified($is_verified) { + $this->isVerified = $is_verified; + return $this; + } + + public function getIsVerified() { + return $this->isVerified; + } + public function setPHID($phid) { $this->phid = $phid; return $this; @@ -104,6 +115,7 @@ final class PhabricatorMetaMTAActor extends Phobject { self::REASON_FORCE_HERALD => pht('Forced by Herald'), self::REASON_ROUTE_AS_NOTIFICATION => pht('Route as Notification'), self::REASON_ROUTE_AS_MAIL => pht('Route as Mail'), + self::REASON_UNVERIFIED => pht('Address Not Verified'), ); return idx($names, $reason, pht('Unknown ("%s")', $reason)); @@ -158,6 +170,8 @@ final class PhabricatorMetaMTAActor extends Phobject { self::REASON_ROUTE_AS_MAIL => pht( 'This message was upgraded to email by outbound mail rules '. 'in Herald.'), + self::REASON_UNVERIFIED => pht( + 'This recipient does not have a verified primary email address.'), ); return idx($descriptions, $reason, pht('Unknown Reason ("%s")', $reason)); diff --git a/src/applications/metamta/query/PhabricatorMetaMTAActorQuery.php b/src/applications/metamta/query/PhabricatorMetaMTAActorQuery.php index 38b04d6883..18b8063ee1 100644 --- a/src/applications/metamta/query/PhabricatorMetaMTAActorQuery.php +++ b/src/applications/metamta/query/PhabricatorMetaMTAActorQuery.php @@ -89,6 +89,7 @@ final class PhabricatorMetaMTAActorQuery extends PhabricatorQuery { $actor->setUndeliverable(PhabricatorMetaMTAActor::REASON_NO_ADDRESS); } else { $actor->setEmailAddress($email->getAddress()); + $actor->setIsVerified($email->getIsVerified()); } } } @@ -119,6 +120,13 @@ final class PhabricatorMetaMTAActorQuery extends PhabricatorQuery { } $actor->setEmailAddress($xuser->getAccountID()); + + // NOTE: This effectively drops all outbound mail to unrecognized + // addresses unless "phabricator.allow-email-users" is set. See T12237 + // for context. + $allow_key = 'phabricator.allow-email-users'; + $allow_value = PhabricatorEnv::getEnvConfig($allow_key); + $actor->setIsVerified((bool)$allow_value); } } diff --git a/src/applications/metamta/receiver/PhabricatorMailReceiver.php b/src/applications/metamta/receiver/PhabricatorMailReceiver.php index 07d364b21f..05b44f364a 100644 --- a/src/applications/metamta/receiver/PhabricatorMailReceiver.php +++ b/src/applications/metamta/receiver/PhabricatorMailReceiver.php @@ -153,6 +153,10 @@ abstract class PhabricatorMailReceiver extends Phobject { ->loadOneOrCreate(); return $xuser->getPhabricatorUser(); } else { + // NOTE: Currently, we'll always drop this mail (since it's headed to + // an unverified recipient). See T12237. These details are still useful + // because they'll appear in the mail logs and Mail web UI. + $reasons[] = pht( 'Phabricator is also not configured to allow unknown external users '. 'to send mail to the system using just an email address.'); @@ -174,13 +178,13 @@ abstract class PhabricatorMailReceiver extends Phobject { if ($user) { return $user; } - } - $reasons[] = pht( - "Phabricator is misconfigured, the application email ". - "'%s' is set to user '%s' but that user does not exist.", - $application_email->getAddress(), - $default_user_phid); + $reasons[] = pht( + 'Phabricator is misconfigured: the application email '. + '"%s" is set to user "%s", but that user does not exist.', + $application_email->getAddress(), + $default_user_phid); + } } $reasons = implode("\n\n", $reasons); diff --git a/src/applications/metamta/storage/PhabricatorMetaMTAMail.php b/src/applications/metamta/storage/PhabricatorMetaMTAMail.php index 0c90e43832..7d8a638401 100644 --- a/src/applications/metamta/storage/PhabricatorMetaMTAMail.php +++ b/src/applications/metamta/storage/PhabricatorMetaMTAMail.php @@ -951,6 +951,16 @@ final class PhabricatorMetaMTAMail } } + // Unless delivery was forced earlier (password resets, confirmation mail), + // never send mail to unverified addresses. + foreach ($actors as $phid => $actor) { + if ($actor->getIsVerified()) { + continue; + } + + $actor->setUndeliverable(PhabricatorMetaMTAActor::REASON_UNVERIFIED); + } + return $actors; } diff --git a/src/applications/metamta/storage/__tests__/PhabricatorMetaMTAMailTestCase.php b/src/applications/metamta/storage/__tests__/PhabricatorMetaMTAMailTestCase.php index 2f892eb084..635913439d 100644 --- a/src/applications/metamta/storage/__tests__/PhabricatorMetaMTAMailTestCase.php +++ b/src/applications/metamta/storage/__tests__/PhabricatorMetaMTAMailTestCase.php @@ -153,6 +153,22 @@ final class PhabricatorMetaMTAMailTestCase extends PhabricatorTestCase { $this->assertTrue( in_array($phid, $mail->buildRecipientList()), 'Recipients restored after tag preference removed.'); + + $email = id(new PhabricatorUserEmail())->loadOneWhere( + 'userPHID = %s AND isPrimary = 1', + $phid); + + $email->setIsVerified(0)->save(); + + $this->assertFalse( + in_array($phid, $mail->buildRecipientList()), + pht('Mail not sent to unverified address.')); + + $email->setIsVerified(1)->save(); + + $this->assertTrue( + in_array($phid, $mail->buildRecipientList()), + pht('Mail sent to verified address.')); } public function testThreadIDHeaders() { From d1c253de9452d9ff3917297da59f09893f6e2ae8 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Thu, 9 Feb 2017 14:17:54 -0800 Subject: [PATCH 15/48] Touch up basic usability of Dashboards Summary: Ref T10390. This mostly shuffles layout into "View" and keepts "Manage" around for Edit/Copy/History. This feels better to me overall. Also tweaked some spacing and color. Test Plan: New Dashboard, edit Dashboard, shuffle panels. Create new panels. {F2684043} Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Maniphest Tasks: T10390 Differential Revision: https://secure.phabricator.com/D17326 --- resources/celerity/map.php | 10 +- src/__phutil_library_map__.php | 8 +- .../PhabricatorDashboardApplication.php | 1 + ...PhabricatorDashboardAddPanelController.php | 3 +- .../PhabricatorDashboardArrangeController.php | 72 ++++++++++++++ .../PhabricatorDashboardCopyController.php | 8 +- .../PhabricatorDashboardEditController.php | 4 +- .../PhabricatorDashboardManageController.php | 63 +++--------- ...habricatorDashboardPanelEditController.php | 4 +- .../PhabricatorDashboardProfileController.php | 95 ++++++++++++++++++ ...bricatorDashboardRemovePanelController.php | 2 +- .../PhabricatorDashboardViewController.php | 60 +++++------- .../PhabricatorDashboardRenderingEngine.php | 30 +++++- .../PhabricatorDashboardSearchEngine.php | 63 ++---------- .../PhabricatorDashboardTransaction.php | 4 +- .../css/application/dashboard/dashboard.css | 97 ++++++++++++------- .../search/application-search-view.css | 4 + 17 files changed, 327 insertions(+), 201 deletions(-) create mode 100644 src/applications/dashboard/controller/PhabricatorDashboardArrangeController.php create mode 100644 src/applications/dashboard/controller/PhabricatorDashboardProfileController.php diff --git a/resources/celerity/map.php b/resources/celerity/map.php index fcf5ff0f50..6af1fce103 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -9,7 +9,7 @@ return array( 'names' => array( 'conpherence.pkg.css' => 'a520d619', 'conpherence.pkg.js' => '6249a1cf', - 'core.pkg.css' => '72ab63ef', + 'core.pkg.css' => '2a5c3505', 'core.pkg.js' => '1fa7c0c5', 'darkconsole.pkg.js' => 'e7393ebb', 'differential.pkg.css' => '4815647b', @@ -55,7 +55,7 @@ return array( 'rsrc/css/application/contentsource/content-source-view.css' => '4b8b05d4', 'rsrc/css/application/countdown/timer.css' => '16c52f5c', 'rsrc/css/application/daemon/bulk-job.css' => 'df9c1d4a', - 'rsrc/css/application/dashboard/dashboard.css' => '226c4dc6', + 'rsrc/css/application/dashboard/dashboard.css' => '005e064e', 'rsrc/css/application/diff/inline-comment-summary.css' => '51efda3a', 'rsrc/css/application/differential/add-comment.css' => 'c47f8c40', 'rsrc/css/application/differential/changeset-view.css' => '6a9bdf9c', @@ -102,7 +102,7 @@ return array( 'rsrc/css/application/releeph/releeph-preview-branch.css' => 'b7a6f4a5', 'rsrc/css/application/releeph/releeph-request-differential-create-dialog.css' => '8d8b92cd', 'rsrc/css/application/releeph/releeph-request-typeahead.css' => '667a48ae', - 'rsrc/css/application/search/application-search-view.css' => '20ae9d85', + 'rsrc/css/application/search/application-search-view.css' => '66ee5d46', 'rsrc/css/application/search/search-results.css' => '64ad079a', 'rsrc/css/application/slowvote/slowvote.css' => 'a94b7230', 'rsrc/css/application/tokens/tokens.css' => '3d0f239e', @@ -556,7 +556,7 @@ return array( 'aphront-tokenizer-control-css' => '9a8cb501', 'aphront-tooltip-css' => '173b9431', 'aphront-typeahead-control-css' => 'd4f16145', - 'application-search-view-css' => '20ae9d85', + 'application-search-view-css' => '66ee5d46', 'auth-css' => '0877ed6e', 'bulk-job-css' => 'df9c1d4a', 'changeset-view-manager' => 'a2828756', @@ -786,7 +786,7 @@ return array( 'phabricator-content-source-view-css' => '4b8b05d4', 'phabricator-core-css' => '9f4cb463', 'phabricator-countdown-css' => '16c52f5c', - 'phabricator-dashboard-css' => '226c4dc6', + 'phabricator-dashboard-css' => '005e064e', 'phabricator-drag-and-drop-file-upload' => '58dea2fa', 'phabricator-draggable-list' => 'bea6e7f4', 'phabricator-fatal-config-template-css' => '8f18fa41', diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 5e38ba042e..01835b98d6 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -2464,6 +2464,7 @@ phutil_register_library_map(array( 'PhabricatorDashboardAddPanelController' => 'applications/dashboard/controller/PhabricatorDashboardAddPanelController.php', 'PhabricatorDashboardApplication' => 'applications/dashboard/application/PhabricatorDashboardApplication.php', 'PhabricatorDashboardArchiveController' => 'applications/dashboard/controller/PhabricatorDashboardArchiveController.php', + 'PhabricatorDashboardArrangeController' => 'applications/dashboard/controller/PhabricatorDashboardArrangeController.php', 'PhabricatorDashboardController' => 'applications/dashboard/controller/PhabricatorDashboardController.php', 'PhabricatorDashboardCopyController' => 'applications/dashboard/controller/PhabricatorDashboardCopyController.php', 'PhabricatorDashboardDAO' => 'applications/dashboard/storage/PhabricatorDashboardDAO.php', @@ -2503,6 +2504,7 @@ phutil_register_library_map(array( 'PhabricatorDashboardPanelTransactionQuery' => 'applications/dashboard/query/PhabricatorDashboardPanelTransactionQuery.php', 'PhabricatorDashboardPanelType' => 'applications/dashboard/paneltype/PhabricatorDashboardPanelType.php', 'PhabricatorDashboardPanelViewController' => 'applications/dashboard/controller/PhabricatorDashboardPanelViewController.php', + 'PhabricatorDashboardProfileController' => 'applications/dashboard/controller/PhabricatorDashboardProfileController.php', 'PhabricatorDashboardProfileMenuItem' => 'applications/search/menuitem/PhabricatorDashboardProfileMenuItem.php', 'PhabricatorDashboardQuery' => 'applications/dashboard/query/PhabricatorDashboardQuery.php', 'PhabricatorDashboardQueryPanelType' => 'applications/dashboard/paneltype/PhabricatorDashboardQueryPanelType.php', @@ -7471,6 +7473,7 @@ phutil_register_library_map(array( 'PhabricatorDashboardAddPanelController' => 'PhabricatorDashboardController', 'PhabricatorDashboardApplication' => 'PhabricatorApplication', 'PhabricatorDashboardArchiveController' => 'PhabricatorDashboardController', + 'PhabricatorDashboardArrangeController' => 'PhabricatorDashboardProfileController', 'PhabricatorDashboardController' => 'PhabricatorController', 'PhabricatorDashboardCopyController' => 'PhabricatorDashboardController', 'PhabricatorDashboardDAO' => 'PhabricatorLiskDAO', @@ -7482,7 +7485,7 @@ phutil_register_library_map(array( 'PhabricatorDashboardInstall' => 'PhabricatorDashboardDAO', 'PhabricatorDashboardLayoutConfig' => 'Phobject', 'PhabricatorDashboardListController' => 'PhabricatorDashboardController', - 'PhabricatorDashboardManageController' => 'PhabricatorDashboardController', + 'PhabricatorDashboardManageController' => 'PhabricatorDashboardProfileController', 'PhabricatorDashboardMovePanelController' => 'PhabricatorDashboardController', 'PhabricatorDashboardNgrams' => 'PhabricatorSearchNgrams', 'PhabricatorDashboardPanel' => array( @@ -7521,6 +7524,7 @@ phutil_register_library_map(array( 'PhabricatorDashboardPanelTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorDashboardPanelType' => 'Phobject', 'PhabricatorDashboardPanelViewController' => 'PhabricatorDashboardController', + 'PhabricatorDashboardProfileController' => 'PhabricatorController', 'PhabricatorDashboardProfileMenuItem' => 'PhabricatorProfileMenuItem', 'PhabricatorDashboardQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorDashboardQueryPanelType' => 'PhabricatorDashboardPanelType', @@ -7535,7 +7539,7 @@ phutil_register_library_map(array( 'PhabricatorDashboardTransactionEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorDashboardTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorDashboardUninstallController' => 'PhabricatorDashboardController', - 'PhabricatorDashboardViewController' => 'PhabricatorDashboardController', + 'PhabricatorDashboardViewController' => 'PhabricatorDashboardProfileController', 'PhabricatorDataCacheSpec' => 'PhabricatorCacheSpec', 'PhabricatorDataNotAttachedException' => 'Exception', 'PhabricatorDatabaseHealthRecord' => 'Phobject', diff --git a/src/applications/dashboard/application/PhabricatorDashboardApplication.php b/src/applications/dashboard/application/PhabricatorDashboardApplication.php index 54ec5db20a..8a39cc2a5f 100644 --- a/src/applications/dashboard/application/PhabricatorDashboardApplication.php +++ b/src/applications/dashboard/application/PhabricatorDashboardApplication.php @@ -27,6 +27,7 @@ final class PhabricatorDashboardApplication extends PhabricatorApplication { 'view/(?P\d+)/' => 'PhabricatorDashboardViewController', 'archive/(?P\d+)/' => 'PhabricatorDashboardArchiveController', 'manage/(?P\d+)/' => 'PhabricatorDashboardManageController', + 'arrange/(?P\d+)/' => 'PhabricatorDashboardArrangeController', 'create/' => 'PhabricatorDashboardEditController', 'copy/(?:(?P\d+)/)?' => 'PhabricatorDashboardCopyController', 'edit/(?:(?P\d+)/)?' => 'PhabricatorDashboardEditController', diff --git a/src/applications/dashboard/controller/PhabricatorDashboardAddPanelController.php b/src/applications/dashboard/controller/PhabricatorDashboardAddPanelController.php index 3e733edb3e..f34bdd06ae 100644 --- a/src/applications/dashboard/controller/PhabricatorDashboardAddPanelController.php +++ b/src/applications/dashboard/controller/PhabricatorDashboardAddPanelController.php @@ -20,7 +20,8 @@ final class PhabricatorDashboardAddPanelController return new Aphront404Response(); } - $redirect_uri = $this->getApplicationURI('manage/'.$dashboard->getID().'/'); + $redirect_uri = $this->getApplicationURI( + 'arrange/'.$dashboard->getID().'/'); $v_panel = $request->getStr('panel'); $e_panel = true; diff --git a/src/applications/dashboard/controller/PhabricatorDashboardArrangeController.php b/src/applications/dashboard/controller/PhabricatorDashboardArrangeController.php new file mode 100644 index 0000000000..cc9fb54639 --- /dev/null +++ b/src/applications/dashboard/controller/PhabricatorDashboardArrangeController.php @@ -0,0 +1,72 @@ +getViewer(); + $id = $request->getURIData('id'); + + $dashboard = id(new PhabricatorDashboardQuery()) + ->setViewer($viewer) + ->withIDs(array($id)) + ->needPanels(true) + ->executeOne(); + if (!$dashboard) { + return new Aphront404Response(); + } + $this->setDashboard($dashboard); + + $can_edit = PhabricatorPolicyFilter::hasCapability( + $viewer, + $dashboard, + PhabricatorPolicyCapability::CAN_EDIT); + + $title = $dashboard->getName(); + $crumbs = $this->buildApplicationCrumbs(); + $crumbs->addTextCrumb(pht('Arrange')); + $header = $this->buildHeaderView(); + + $info_view = null; + if (!$can_edit) { + $no_edit = pht( + 'You do not have permission to edit this dashboard. If you want to '. + 'make changes, make a copy first.'); + + $info_view = id(new PHUIInfoView()) + ->setSeverity(PHUIInfoView::SEVERITY_NOTICE) + ->setErrors(array($no_edit)); + } + + $rendered_dashboard = id(new PhabricatorDashboardRenderingEngine()) + ->setViewer($viewer) + ->setDashboard($dashboard) + ->setArrangeMode($can_edit) + ->renderDashboard(); + + $dashboard_box = id(new PHUIBoxView()) + ->addClass('dashboard-preview-box') + ->appendChild($rendered_dashboard); + + $view = id(new PHUITwoColumnView()) + ->setHeader($header) + ->setFooter(array( + $info_view, + $dashboard_box, + )); + + $navigation = $this->buildSideNavView('arrange'); + + return $this->newPage() + ->setTitle($title) + ->setCrumbs($crumbs) + ->setNavigation($navigation) + ->appendChild($view); + + } + +} diff --git a/src/applications/dashboard/controller/PhabricatorDashboardCopyController.php b/src/applications/dashboard/controller/PhabricatorDashboardCopyController.php index 6b89915c76..a84eb479b5 100644 --- a/src/applications/dashboard/controller/PhabricatorDashboardCopyController.php +++ b/src/applications/dashboard/controller/PhabricatorDashboardCopyController.php @@ -16,7 +16,7 @@ final class PhabricatorDashboardCopyController return new Aphront404Response(); } - $manage_uri = $this->getApplicationURI('manage/'.$dashboard->getID().'/'); + $cancel_uri = $this->getApplicationURI('manage/'.$dashboard->getID().'/'); if ($request->isFormPost()) { @@ -45,8 +45,8 @@ final class PhabricatorDashboardCopyController ->setContinueOnNoEffect(true) ->applyTransactions($copy, $xactions); - $manage_uri = $this->getApplicationURI('edit/'.$copy->getID().'/'); - return id(new AphrontRedirectResponse())->setURI($manage_uri); + $cancel_uri = $this->getApplicationURI('edit/'.$copy->getID().'/'); + return id(new AphrontRedirectResponse())->setURI($cancel_uri); } return $this->newDialog() @@ -55,7 +55,7 @@ final class PhabricatorDashboardCopyController pht( 'Create a copy of the dashboard "%s"?', phutil_tag('strong', array(), $dashboard->getName()))) - ->addCancelButton($manage_uri) + ->addCancelButton($cancel_uri) ->addSubmitButton(pht('Create Copy')); } diff --git a/src/applications/dashboard/controller/PhabricatorDashboardEditController.php b/src/applications/dashboard/controller/PhabricatorDashboardEditController.php index 09ab373950..0edda37102 100644 --- a/src/applications/dashboard/controller/PhabricatorDashboardEditController.php +++ b/src/applications/dashboard/controller/PhabricatorDashboardEditController.php @@ -117,7 +117,7 @@ final class PhabricatorDashboardEditController ->setContentSourceFromRequest($request) ->applyTransactions($dashboard, $xactions); - $uri = $this->getApplicationURI('manage/'.$dashboard->getID().'/'); + $uri = $this->getApplicationURI('arrange/'.$dashboard->getID().'/'); return id(new AphrontRedirectResponse())->setURI($uri); } catch (PhabricatorApplicationTransactionValidationException $ex) { @@ -351,7 +351,7 @@ final class PhabricatorDashboardEditController ->setContentSourceFromRequest($request) ->applyTransactions($dashboard, $xactions); - $manage_uri = $this->getApplicationURI('manage/'.$dashboard->getID().'/'); + $manage_uri = $this->getApplicationURI('arrange/'.$dashboard->getID().'/'); return id(new AphrontRedirectResponse()) ->setURI($manage_uri); diff --git a/src/applications/dashboard/controller/PhabricatorDashboardManageController.php b/src/applications/dashboard/controller/PhabricatorDashboardManageController.php index d5902ce93d..70027a7332 100644 --- a/src/applications/dashboard/controller/PhabricatorDashboardManageController.php +++ b/src/applications/dashboard/controller/PhabricatorDashboardManageController.php @@ -1,14 +1,16 @@ getViewer(); $id = $request->getURIData('id'); - $dashboard_uri = $this->getApplicationURI('view/'.$id.'/'); - // TODO: This UI should drop a lot of capabilities if the user can't // edit the dashboard, but we should still let them in for "Install" and // "View History". @@ -21,6 +23,7 @@ final class PhabricatorDashboardManageController if (!$dashboard) { return new Aphront404Response(); } + $this->setDashboard($dashboard); $can_edit = PhabricatorPolicyFilter::hasCapability( $viewer, @@ -30,19 +33,16 @@ final class PhabricatorDashboardManageController $title = $dashboard->getName(); $crumbs = $this->buildApplicationCrumbs(); - $crumbs->addTextCrumb( - pht('Dashboard %d', $dashboard->getID()), - $dashboard_uri); $crumbs->addTextCrumb(pht('Manage')); - $crumbs->setBorder(true); - $header = $this->buildHeaderView($dashboard); + $header = $this->buildHeaderView(); $curtain = $this->buildCurtainview($dashboard); $properties = $this->buildPropertyView($dashboard); $timeline = $this->buildTransactionTimeline( $dashboard, new PhabricatorDashboardTransactionQuery()); + $timeline->setShouldTerminate(true); $info_view = null; if (!$can_edit) { @@ -55,16 +55,6 @@ final class PhabricatorDashboardManageController ->setErrors(array($no_edit)); } - $rendered_dashboard = id(new PhabricatorDashboardRenderingEngine()) - ->setViewer($viewer) - ->setDashboard($dashboard) - ->setArrangeMode($can_edit) - ->renderDashboard(); - - $dashboard_box = id(new PHUIBoxView()) - ->addClass('dashboard-preview-box') - ->appendChild($rendered_dashboard); - $view = id(new PHUITwoColumnView()) ->setHeader($header) ->setCurtain($curtain) @@ -72,47 +62,18 @@ final class PhabricatorDashboardManageController $info_view, $properties, $timeline, - )) - ->setFooter($dashboard_box); + )); + + $navigation = $this->buildSideNavView('manage'); return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) + ->setNavigation($navigation) ->appendChild($view); } - private function buildHeaderView(PhabricatorDashboard $dashboard) { - $viewer = $this->getViewer(); - $id = $dashboard->getID(); - - if ($dashboard->isArchived()) { - $status_icon = 'fa-ban'; - $status_color = 'dark'; - } else { - $status_icon = 'fa-check'; - $status_color = 'bluegrey'; - } - - $status_name = idx( - PhabricatorDashboard::getStatusNameMap(), - $dashboard->getStatus()); - - $button = id(new PHUIButtonView()) - ->setTag('a') - ->setText(pht('View Dashboard')) - ->setIcon('fa-columns') - ->setHref($this->getApplicationURI("view/{$id}/")); - - return id(new PHUIHeaderView()) - ->setUser($viewer) - ->setHeader($dashboard->getName()) - ->setPolicyObject($dashboard) - ->setStatus($status_icon, $status_color, $status_name) - ->setHeaderIcon($dashboard->getIcon()) - ->addActionLink($button); - } - private function buildCurtainView(PhabricatorDashboard $dashboard) { $viewer = $this->getViewer(); $id = $dashboard->getID(); diff --git a/src/applications/dashboard/controller/PhabricatorDashboardPanelEditController.php b/src/applications/dashboard/controller/PhabricatorDashboardPanelEditController.php index 787d1c63ee..6ebf0f2eba 100644 --- a/src/applications/dashboard/controller/PhabricatorDashboardPanelEditController.php +++ b/src/applications/dashboard/controller/PhabricatorDashboardPanelEditController.php @@ -26,7 +26,7 @@ final class PhabricatorDashboardPanelEditController return new Aphront404Response(); } - $manage_uri = $this->getApplicationURI('manage/'.$dashboard_id.'/'); + $manage_uri = $this->getApplicationURI('arrange/'.$dashboard_id.'/'); } if ($id) { @@ -372,7 +372,7 @@ final class PhabricatorDashboardPanelEditController $viewer = $request->getUser(); - $manage_uri = $this->getApplicationURI('manage/'.$dashboard->getID().'/'); + $manage_uri = $this->getApplicationURI('arrange/'.$dashboard->getID().'/'); return $this->newDialog() ->setTitle(pht('Copy Panel?')) diff --git a/src/applications/dashboard/controller/PhabricatorDashboardProfileController.php b/src/applications/dashboard/controller/PhabricatorDashboardProfileController.php new file mode 100644 index 0000000000..6a23b351ac --- /dev/null +++ b/src/applications/dashboard/controller/PhabricatorDashboardProfileController.php @@ -0,0 +1,95 @@ +dashboard = $dashboard; + return $this; + } + + public function getDashboard() { + return $this->dashboard; + } + + public function buildApplicationMenu() { + return $this->buildSideNavView()->getMenu(); + } + + protected function buildHeaderView() { + $viewer = $this->getViewer(); + $dashboard = $this->getDashboard(); + $id = $dashboard->getID(); + + if ($dashboard->isArchived()) { + $status_icon = 'fa-ban'; + $status_color = 'dark'; + } else { + $status_icon = 'fa-check'; + $status_color = 'bluegrey'; + } + + $status_name = idx( + PhabricatorDashboard::getStatusNameMap(), + $dashboard->getStatus()); + + return id(new PHUIHeaderView()) + ->setUser($viewer) + ->setHeader($dashboard->getName()) + ->setPolicyObject($dashboard) + ->setStatus($status_icon, $status_color, $status_name) + ->setHeaderIcon($dashboard->getIcon()); + } + + protected function buildApplicationCrumbs() { + $dashboard = $this->getDashboard(); + $id = $dashboard->getID(); + $dashboard_uri = $this->getApplicationURI("/view/{$id}/"); + + $crumbs = parent::buildApplicationCrumbs(); + $crumbs->addTextCrumb($dashboard->getName(), $dashboard_uri); + $crumbs->setBorder(true); + return $crumbs; + } + + protected function buildSideNavView($filter = null) { + $viewer = $this->getViewer(); + $dashboard = $this->getDashboard(); + $id = $dashboard->getID(); + + $can_edit = PhabricatorPolicyFilter::hasCapability( + $viewer, + $dashboard, + PhabricatorPolicyCapability::CAN_EDIT); + + $nav = id(new AphrontSideNavFilterView()) + ->setBaseURI(new PhutilURI($this->getApplicationURI())); + + $nav->addLabel(pht('Dashboard')); + + $nav->addFilter( + 'view', + pht('View Dashboard'), + $this->getApplicationURI("/view/{$id}/"), + 'fa-dashboard'); + + $nav->addFilter( + 'arrange', + pht('Arrange Panels'), + $this->getApplicationURI("/arrange/{$id}/"), + 'fa-columns'); + + $nav->addFilter( + 'manage', + pht('Manage Dashboard'), + $this->getApplicationURI("/manage/{$id}/"), + 'fa-gears'); + + $nav->selectFilter($filter); + + return $nav; + } + +} diff --git a/src/applications/dashboard/controller/PhabricatorDashboardRemovePanelController.php b/src/applications/dashboard/controller/PhabricatorDashboardRemovePanelController.php index c30b06c596..d62b163db2 100644 --- a/src/applications/dashboard/controller/PhabricatorDashboardRemovePanelController.php +++ b/src/applications/dashboard/controller/PhabricatorDashboardRemovePanelController.php @@ -43,7 +43,7 @@ final class PhabricatorDashboardRemovePanelController } $redirect_uri = $this->getApplicationURI( - 'manage/'.$dashboard->getID().'/'); + 'arrange/'.$dashboard->getID().'/'); $layout_config = $dashboard->getLayoutConfigObject(); if ($request->isFormPost()) { diff --git a/src/applications/dashboard/controller/PhabricatorDashboardViewController.php b/src/applications/dashboard/controller/PhabricatorDashboardViewController.php index dd2214df24..547398f3fd 100644 --- a/src/applications/dashboard/controller/PhabricatorDashboardViewController.php +++ b/src/applications/dashboard/controller/PhabricatorDashboardViewController.php @@ -1,9 +1,7 @@ getViewer(); - $this->id = $request->getURIData('id'); + $id = $request->getURIData('id'); $dashboard = id(new PhabricatorDashboardQuery()) ->setViewer($viewer) - ->withIDs(array($this->id)) + ->withIDs(array($id)) ->needPanels(true) ->executeOne(); if (!$dashboard) { return new Aphront404Response(); } + $this->setDashboard($dashboard); + $dashboard_uri = $this->getApplicationURI("view/{$id}/"); $title = $dashboard->getName(); $crumbs = $this->buildApplicationCrumbs(); - $crumbs->setBorder(true); - $crumbs->addTextCrumb(pht('Dashboard %d', $dashboard->getID())); + $crumbs->addTextCrumb(pht('View')); if ($dashboard->getPanelPHIDs()) { $rendered_dashboard = id(new PhabricatorDashboardRenderingEngine()) ->setViewer($viewer) ->setDashboard($dashboard) ->renderDashboard(); + $content = id(new PHUIBoxView()) + ->addClass('dashboard-preview-box') + ->appendChild($rendered_dashboard); } else { - $rendered_dashboard = $this->buildEmptyView(); + $content = id(new PHUIInfoView()) + ->setSeverity(PHUIInfoView::SEVERITY_NOTICE) + ->appendChild(pht('This dashboard has no panels yet.')); } + $navigation = $this->buildSideNavView('view'); + $header = $this->buildHeaderView(); + + $view = id(new PHUITwoColumnView()) + ->setHeader($header) + ->setFooter(array( + $content, + )); + return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) - ->appendChild($rendered_dashboard); - } - - protected function buildApplicationCrumbs() { - $crumbs = parent::buildApplicationCrumbs(); - $id = $this->id; - - $crumbs->addAction( - id(new PHUIListItemView()) - ->setIcon('fa-th') - ->setName(pht('Manage Dashboard')) - ->setHref($this->getApplicationURI("manage/{$id}/"))); - - return $crumbs; - } - - public function buildEmptyView() { - $id = $this->id; - $manage_uri = $this->getApplicationURI("manage/{$id}/"); - - return id(new PHUIInfoView()) - ->setSeverity(PHUIInfoView::SEVERITY_NODATA) - ->appendChild( - pht('This dashboard has no panels '. - 'yet. Use %s to add panels.', - phutil_tag( - 'a', - array('href' => $manage_uri), - pht('Manage Dashboard')))); + ->setNavigation($navigation) + ->appendChild($view); } } diff --git a/src/applications/dashboard/engine/PhabricatorDashboardRenderingEngine.php b/src/applications/dashboard/engine/PhabricatorDashboardRenderingEngine.php index d1e1d3111c..b817684a64 100644 --- a/src/applications/dashboard/engine/PhabricatorDashboardRenderingEngine.php +++ b/src/applications/dashboard/engine/PhabricatorDashboardRenderingEngine.php @@ -81,17 +81,43 @@ final class PhabricatorDashboardRenderingEngine extends Phobject { } if ($this->arrangeMode) { + $footer = null; Javelin::initBehavior( 'dashboard-move-panels', array( 'dashboardID' => $dashboard_id, 'moveURI' => '/dashboard/movepanel/'.$dashboard->getID().'/', )); + } else { + $name = $dashboard->getName(); + $icon = id(new PHUIIconView()) + ->setIcon($dashboard->getIcon()) + ->addClass('msr'); + $footer_left = phutil_tag( + 'a', + array( + 'class' => 'dashboard-footer-name', + 'href' => '/dashboard/view/'.$dashboard->getID().'/', + ), + array( + $icon, + $name, + )); + + $footer = phutil_tag( + 'div', + array( + 'class' => 'dashboard-footer-view', + ), + array( + $footer_left, + )); } $view = id(new PHUIBoxView()) ->addClass('dashboard-view') - ->appendChild($result); + ->appendChild($result) + ->appendChild($footer); return $view; } @@ -123,7 +149,6 @@ final class PhabricatorDashboardRenderingEngine extends Phobject { ->setTag('a') ->setHref($create_uri) ->setWorkflow(true) - ->setColor(PHUIButtonView::GREY) ->setText(pht('Create Panel')) ->addClass(PHUI::MARGIN_MEDIUM); @@ -131,7 +156,6 @@ final class PhabricatorDashboardRenderingEngine extends Phobject { ->setTag('a') ->setHref($add_uri) ->setWorkflow(true) - ->setColor(PHUIButtonView::GREY) ->setText(pht('Add Existing Panel')) ->addClass(PHUI::MARGIN_MEDIUM); diff --git a/src/applications/dashboard/query/PhabricatorDashboardSearchEngine.php b/src/applications/dashboard/query/PhabricatorDashboardSearchEngine.php index c6c6ab1233..56f766c089 100644 --- a/src/applications/dashboard/query/PhabricatorDashboardSearchEngine.php +++ b/src/applications/dashboard/query/PhabricatorDashboardSearchEngine.php @@ -101,20 +101,6 @@ final class PhabricatorDashboardSearchEngine $dashboards = mpull($dashboards, null, 'getPHID'); $viewer = $this->requireViewer(); - if ($dashboards) { - $installs = id(new PhabricatorDashboardInstall()) - ->loadAllWhere( - 'objectPHID IN (%Ls) AND dashboardPHID IN (%Ls)', - array( - PhabricatorHomeApplication::DASHBOARD_DEFAULT, - $viewer->getPHID(), - ), - array_keys($dashboards)); - $installs = mpull($installs, null, 'getDashboardPHID'); - } else { - $installs = array(); - } - $proj_phids = array(); foreach ($dashboards as $dashboard) { foreach ($dashboard->getProjectPHIDs() as $project_phid) { @@ -127,37 +113,18 @@ final class PhabricatorDashboardSearchEngine ->withPHIDs($proj_phids) ->execute(); - $list = new PHUIObjectItemListView(); - $list->setUser($viewer); - $list->initBehavior('phabricator-tooltips', array()); - $list->requireResource('aphront-tooltip-css'); + $list = id(new PHUIObjectItemListView()) + ->setUser($viewer); foreach ($dashboards as $dashboard_phid => $dashboard) { $id = $dashboard->getID(); $item = id(new PHUIObjectItemView()) - ->setObjectName(pht('Dashboard %d', $id)) + ->setUser($viewer) ->setHeader($dashboard->getName()) ->setHref($this->getApplicationURI("view/{$id}/")) ->setObject($dashboard); - if (isset($installs[$dashboard_phid])) { - $install = $installs[$dashboard_phid]; - if ($install->getObjectPHID() == $viewer->getPHID()) { - $attrs = array( - 'tip' => pht( - 'This dashboard is installed to your personal homepage.'), - ); - $item->addIcon('fa-user', pht('Installed'), $attrs); - } else { - $attrs = array( - 'tip' => pht( - 'This dashboard is the default homepage for all users.'), - ); - $item->addIcon('fa-globe', pht('Installed'), $attrs); - } - } - $project_handles = array_select_keys( $proj_handles, $dashboard->getProjectPHIDs()); @@ -173,25 +140,11 @@ final class PhabricatorDashboardSearchEngine $item->setDisabled(true); } - $can_edit = PhabricatorPolicyFilter::hasCapability( - $viewer, - $dashboard, - PhabricatorPolicyCapability::CAN_EDIT); - - $href_view = $this->getApplicationURI("manage/{$id}/"); - $item->addAction( - id(new PHUIListItemView()) - ->setName(pht('Manage')) - ->setIcon('fa-th') - ->setHref($href_view)); - - $href_edit = $this->getApplicationURI("edit/{$id}/"); - $item->addAction( - id(new PHUIListItemView()) - ->setName(pht('Edit')) - ->setIcon('fa-pencil') - ->setHref($href_edit) - ->setDisabled(!$can_edit)); + $icon = id(new PHUIIconView()) + ->setIcon($dashboard->getIcon()) + ->setBackground('bg-dark'); + $item->setImageIcon($icon); + $item->setEpoch($dashboard->getDateModified()); $list->addItem($item); } diff --git a/src/applications/dashboard/storage/PhabricatorDashboardTransaction.php b/src/applications/dashboard/storage/PhabricatorDashboardTransaction.php index 1511078f11..a4a6c7f8b1 100644 --- a/src/applications/dashboard/storage/PhabricatorDashboardTransaction.php +++ b/src/applications/dashboard/storage/PhabricatorDashboardTransaction.php @@ -56,11 +56,11 @@ final class PhabricatorDashboardTransaction case self::TYPE_STATUS: if ($new == PhabricatorDashboard::STATUS_ACTIVE) { return pht( - '%s activated this dashboard', + '%s activated this dashboard.', $author_link); } else { return pht( - '%s archived this dashboard', + '%s archived this dashboard.', $author_link); } break; diff --git a/webroot/rsrc/css/application/dashboard/dashboard.css b/webroot/rsrc/css/application/dashboard/dashboard.css index ace968a8eb..8bce842053 100644 --- a/webroot/rsrc/css/application/dashboard/dashboard.css +++ b/webroot/rsrc/css/application/dashboard/dashboard.css @@ -35,63 +35,88 @@ } .device-desktop .aphront-multi-column-fluid .aphront-multi-column-2-up -.aphront-multi-column-column-outer.half { - width: 50%; + .aphront-multi-column-column-outer.half { + width: 50%; } .device-desktop .aphront-multi-column-fluid .aphront-multi-column-2-up -.aphront-multi-column-column-outer.third { - width: 33.34%; + .aphront-multi-column-column-outer.third { + width: 33.34%; } .device-desktop .aphront-multi-column-fluid .aphront-multi-column-2-up -.aphront-multi-column-column-outer.thirds { - width: 66.66%; + .aphront-multi-column-column-outer.thirds { + width: 66.66%; } -.aphront-multi-column-fluid -.aphront-multi-column-column-outer.grippable -.aphront-multi-column-column .dashboard-pane { +.grippable .aphront-multi-column-column .dashboard-pane .phui-object-box { cursor: move; } -.aphront-multi-column-fluid -.aphront-multi-column-column .drag-ghost { +.grippable .aphront-multi-column-column .dashboard-pane .phui-object-box:hover { + box-shadow: {$dropshadow}; +} + +.grippable .aphront-multi-column-column .dashboard-pane .phui-object-box:hover + .phui-object-box { + box-shadow: none; +} + +.aphront-multi-column-fluid .aphront-multi-column-column .drag-ghost { list-style-type: none; - margin: 16px; } -.aphront-multi-column-fluid -.aphront-multi-column-column -.dashboard-panel-placeholder { - display: none; +.aphront-multi-column-fluid .aphront-multi-column-column + .dashboard-panel-placeholder { + display: none; } -.aphront-multi-column-fluid -.aphront-multi-column-column.dashboard-column-empty -.dashboard-panel-placeholder { - display: block; - padding: 20px; - margin: 0 0 12px 0; - text-decoration: none; - border: 1px {$greyborder} dashed; - color: {$greytext}; +.aphront-multi-column-fluid .aphront-multi-column-column.dashboard-column-empty + .dashboard-panel-placeholder { + display: block; + padding: 20px; + margin: 0 0 12px 0; + text-decoration: none; + border: 1px {$greyborder} dashed; + color: {$greytext}; } -.aphront-multi-column-fluid -.aphront-multi-column-column.drag-target-list -.dashboard-panel-placeholder { - display: none; +.aphront-multi-column-fluid .aphront-multi-column-column.drag-target-list + .dashboard-panel-placeholder { + display: none; } -.aphront-multi-column-fluid -.aphront-multi-column-column-outer -.aphront-multi-column-column .phui-info-view { - margin: 0; +.aphront-multi-column-fluid .aphront-multi-column-column-outer + .aphront-multi-column-column .phui-info-view { + margin: 0; } .dashboard-preview-box { - border: 1px solid {$lightblueborder}; - border-radius: 3px; - background-color: rgba(255,255,255,.33); + margin: -16px -16px 16px; +} + +.phui-info-view + .dashboard-preview-box { + margin-top: 0; +} + +.drag-frame .phui-object-box { + box-shadow: {$dropshadow}; +} + +.drag-frame .phui-object-box .phui-object-box { + box-shadow: none; +} + +/*** Footer *******************************************************************/ + +.dashboard-footer-view { + background-color: {$page.sidenav}; + padding: 8px 16px; + border-radius: 3px; +} + +.dashboard-footer-name { + color: {$darkbluetext}; + font-weight: bold; + -webkit-font-smoothing: antialiased; } diff --git a/webroot/rsrc/css/application/search/application-search-view.css b/webroot/rsrc/css/application/search/application-search-view.css index aa1b5c4f97..1964d010f0 100644 --- a/webroot/rsrc/css/application/search/application-search-view.css +++ b/webroot/rsrc/css/application/search/application-search-view.css @@ -67,3 +67,7 @@ .device-phone .application-search-pager { margin: 12px; } + +.application-search-view .phui-oi-list-view.phui-oi-list-big { + margin-top: 12px; +} From 56b1ff833b12998f5d383b108f7f315707d50584 Mon Sep 17 00:00:00 2001 From: epriestley Date: Fri, 10 Feb 2017 06:32:04 -0800 Subject: [PATCH 16/48] Fix some outdated help text about "Reply All" in "metamta.one-mail-per-recipient" Summary: Ref T12240. When you "Reply All" to a Phabricator mail, we make an effort not to send the response to recipients who you hit with the original message. This isn't perfect and we can't always get it right, but the old description implies it's a bigger problem than it should be in practice. Test Plan: Read text. Reviewers: chad, eadler Reviewed By: chad Maniphest Tasks: T12240 Differential Revision: https://secure.phabricator.com/D17331 --- .../config/option/PhabricatorMetaMTAConfigOptions.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/applications/config/option/PhabricatorMetaMTAConfigOptions.php b/src/applications/config/option/PhabricatorMetaMTAConfigOptions.php index 806cd02db3..556b1b169a 100644 --- a/src/applications/config/option/PhabricatorMetaMTAConfigOptions.php +++ b/src/applications/config/option/PhabricatorMetaMTAConfigOptions.php @@ -61,9 +61,10 @@ of each approach are: a normal recipient and also Cc'd on a mailing list. - Getting threading to work properly is harder, and probably requires making mail less useful by turning off options. - - Sometimes people will "Reply All" and everyone will get two mails, - one from the user and one from Phabricator turning their mail into - a comment. + - Sometimes people will "Reply All", which can send mail to too many + recipients. Phabricator will try not to send mail to users who already + received a similar message, but can not prevent all stray email arising + from "Reply All". - Not supported with a private reply-to address. - Mails are sent in the server default translation. - One mail to each user: @@ -73,7 +74,8 @@ of each approach are: mail. - Getting threading to work properly is easier, and threading settings can be customzied by each user. - - "Reply All" no longer spams all other users. + - "Reply All" will never send extra mail to other users involved in the + thread. - Required if private reply-to addresses are configured. - Mails are sent in the language of user preference. From 743dc9fdb514667ead11c41b386218f0f72a55ae Mon Sep 17 00:00:00 2001 From: epriestley Date: Fri, 10 Feb 2017 06:46:51 -0800 Subject: [PATCH 17/48] Stop "Header" fields (labels for form sections) from trying to generate Conduit edits Summary: Fixes T12236. Headers are currently trying to generate an edit transaction for `maniphest.edit` and similar, but should not, since you can't edit them. Test Plan: - Configured Maniphest with a custom header field. - Before change: `maniphest.edit` API console page fataled. - After change: all good, no weird "header" transaction. - Header still shows up on "Edit Task" form in web UI. Reviewers: chad Reviewed By: chad Maniphest Tasks: T12236 Differential Revision: https://secure.phabricator.com/D17332 --- .../standard/PhabricatorStandardCustomFieldHeader.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldHeader.php b/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldHeader.php index b95531538a..beb92f9aed 100644 --- a/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldHeader.php +++ b/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldHeader.php @@ -34,4 +34,8 @@ final class PhabricatorStandardCustomFieldHeader return false; } + public function shouldAppearInConduitTransactions() { + return false; + } + } From 4039f5f11b713371b0b64dfb9bee10ee4afb961f Mon Sep 17 00:00:00 2001 From: epriestley Date: Fri, 10 Feb 2017 08:34:12 -0800 Subject: [PATCH 18/48] Don't try to access the Stripe object until the user submits the credit card form Summary: Ref T12232. I can't reproduce the original issue, but this should probably fix it without side effects? Test Plan: Added a card with Stripe, but I could do that before too. Reviewers: chad Reviewed By: chad Maniphest Tasks: T12232 Differential Revision: https://secure.phabricator.com/D17333 --- resources/celerity/map.php | 14 +++++++------- .../phortune/behavior-stripe-payment-form.js | 3 ++- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/resources/celerity/map.php b/resources/celerity/map.php index 6af1fce103..eb049533cd 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -433,7 +433,7 @@ return array( 'rsrc/js/application/passphrase/passphrase-credential-control.js' => '3cb0b2fc', 'rsrc/js/application/pholio/behavior-pholio-mock-edit.js' => 'bee502c8', 'rsrc/js/application/pholio/behavior-pholio-mock-view.js' => 'fbe497e7', - 'rsrc/js/application/phortune/behavior-stripe-payment-form.js' => '3f5d6dbf', + 'rsrc/js/application/phortune/behavior-stripe-payment-form.js' => 'a6b98425', 'rsrc/js/application/phortune/behavior-test-payment-form.js' => 'fc91ab6c', 'rsrc/js/application/phortune/phortune-credit-card-form.js' => '2290aeef', 'rsrc/js/application/policy/behavior-policy-control.js' => 'd0c516d5', @@ -712,7 +712,7 @@ return array( 'javelin-behavior-select-on-click' => '4e3e79a6', 'javelin-behavior-setup-check-https' => '491416b3', 'javelin-behavior-slowvote-embed' => '887ad43f', - 'javelin-behavior-stripe-payment-form' => '3f5d6dbf', + 'javelin-behavior-stripe-payment-form' => 'a6b98425', 'javelin-behavior-test-payment-form' => 'fc91ab6c', 'javelin-behavior-time-typeahead' => '522431f7', 'javelin-behavior-toggle-class' => '92b9ec77', @@ -1161,11 +1161,6 @@ return array( 'javelin-workflow', 'javelin-stratcom', ), - '3f5d6dbf' => array( - 'javelin-behavior', - 'javelin-dom', - 'phortune-credit-card-form', - ), '40a6a403' => array( 'javelin-install', 'javelin-dom', @@ -1761,6 +1756,11 @@ return array( 'phuix-icon-view', 'phabricator-busy', ), + 'a6b98425' => array( + 'javelin-behavior', + 'javelin-dom', + 'phortune-credit-card-form', + ), 'a6f7a73b' => array( 'javelin-behavior', 'javelin-stratcom', diff --git a/webroot/rsrc/js/application/phortune/behavior-stripe-payment-form.js b/webroot/rsrc/js/application/phortune/behavior-stripe-payment-form.js index 7921a52744..2d4b4758ba 100644 --- a/webroot/rsrc/js/application/phortune/behavior-stripe-payment-form.js +++ b/webroot/rsrc/js/application/phortune/behavior-stripe-payment-form.js @@ -6,11 +6,12 @@ */ JX.behavior('stripe-payment-form', function(config) { - Stripe.setPublishableKey(config.stripePublishableKey); function onsubmit(card_data) { var errors = []; + Stripe.setPublishableKey(config.stripePublishableKey); + if (!Stripe.validateCardNumber(card_data.number)) { errors.push('cc:invalid:number'); } From e0675b28d8e60d5b08c7dd26005c5d1efc5219b2 Mon Sep 17 00:00:00 2001 From: Josh Cox Date: Wed, 8 Feb 2017 13:13:32 -0500 Subject: [PATCH 19/48] Pass exception to PhutilProxyException Summary: Fixes T12243. That error occured due to network flakiness with some mounted filesystems so I'm not sure how best to simulate it. But you can look and see that the PhutilProxyException does indeed expect an exception as its second arg. Test Plan: Look at method signature... look at callsite... now back at the method. Smile and nod. Reviewers: #blessed_reviewers, yelirekim, epriestley Reviewed By: #blessed_reviewers, epriestley Subscribers: epriestley Maniphest Tasks: T12243 Differential Revision: https://secure.phabricator.com/D17335 --- .../diffusion/protocol/DiffusionRepositoryClusterEngine.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/applications/diffusion/protocol/DiffusionRepositoryClusterEngine.php b/src/applications/diffusion/protocol/DiffusionRepositoryClusterEngine.php index 4bb9ca6255..e87c798e28 100644 --- a/src/applications/diffusion/protocol/DiffusionRepositoryClusterEngine.php +++ b/src/applications/diffusion/protocol/DiffusionRepositoryClusterEngine.php @@ -335,7 +335,8 @@ final class DiffusionRepositoryClusterEngine extends Phobject { pht( 'Failed to acquire write lock after waiting %s second(s). You '. 'may be able to retry later.', - new PhutilNumber($lock_wait))); + new PhutilNumber($lock_wait)), + $ex); } $versions = PhabricatorRepositoryWorkingCopyVersion::loadVersions( From 4176bdeb5be0a2a56a1b1ccc67915ec13469ca99 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Fri, 10 Feb 2017 10:38:00 -0800 Subject: [PATCH 20/48] Allow task graph task titles to go full width Summary: Fixes T12213. Removes truncation and allows titles to be full width if needed. Test Plan: Chrome / Firefox / Safari on Mac, mobile and desktop widths. {F2754679} Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Maniphest Tasks: T12213 Differential Revision: https://secure.phabricator.com/D17336 --- resources/celerity/map.php | 6 +++--- src/infrastructure/graph/ManiphestTaskGraph.php | 6 +----- webroot/rsrc/css/aphront/table-view.css | 4 ++++ 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/resources/celerity/map.php b/resources/celerity/map.php index eb049533cd..fd063fd5cb 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -9,7 +9,7 @@ return array( 'names' => array( 'conpherence.pkg.css' => 'a520d619', 'conpherence.pkg.js' => '6249a1cf', - 'core.pkg.css' => '2a5c3505', + 'core.pkg.css' => '76a0e8c9', 'core.pkg.js' => '1fa7c0c5', 'darkconsole.pkg.js' => 'e7393ebb', 'differential.pkg.css' => '4815647b', @@ -27,7 +27,7 @@ return array( 'rsrc/css/aphront/notification.css' => '3f6c89c9', 'rsrc/css/aphront/panel-view.css' => '8427b78d', 'rsrc/css/aphront/phabricator-nav-view.css' => 'e58a4a30', - 'rsrc/css/aphront/table-view.css' => '213a5981', + 'rsrc/css/aphront/table-view.css' => '6ca8e057', 'rsrc/css/aphront/tokenizer.css' => '9a8cb501', 'rsrc/css/aphront/tooltip.css' => '173b9431', 'rsrc/css/aphront/typeahead-browse.css' => '8904346a', @@ -552,7 +552,7 @@ return array( 'aphront-list-filter-view-css' => '5d6f0526', 'aphront-multi-column-view-css' => '84cc6640', 'aphront-panel-view-css' => '8427b78d', - 'aphront-table-view-css' => '213a5981', + 'aphront-table-view-css' => '6ca8e057', 'aphront-tokenizer-control-css' => '9a8cb501', 'aphront-tooltip-css' => '173b9431', 'aphront-typeahead-control-css' => 'd4f16145', diff --git a/src/infrastructure/graph/ManiphestTaskGraph.php b/src/infrastructure/graph/ManiphestTaskGraph.php index a306241f85..24e463e273 100644 --- a/src/infrastructure/graph/ManiphestTaskGraph.php +++ b/src/infrastructure/graph/ManiphestTaskGraph.php @@ -53,17 +53,13 @@ final class ManiphestTaskGraph $full_title = $object->getTitle(); - $title = id(new PhutilUTF8StringTruncator()) - ->setMaximumGlyphs(80) - ->truncateString($full_title); - $link = phutil_tag( 'a', array( 'href' => $object->getURI(), 'title' => $full_title, ), - $title); + $full_title); $link = array( phutil_tag( diff --git a/webroot/rsrc/css/aphront/table-view.css b/webroot/rsrc/css/aphront/table-view.css index 1d59435e3b..8ea7691130 100644 --- a/webroot/rsrc/css/aphront/table-view.css +++ b/webroot/rsrc/css/aphront/table-view.css @@ -232,6 +232,10 @@ span.single-display-line-content { .aphront-table-view td.object-link { white-space: nowrap; + word-wrap: break-word; + overflow: hidden; + text-overflow: ellipsis; + max-width: 0; } .aphront-table-view tr.closed td.object-link .object-name, From 29dc9e9ae1d31c067b2441340fcc672651606675 Mon Sep 17 00:00:00 2001 From: epriestley Date: Fri, 10 Feb 2017 08:48:29 -0800 Subject: [PATCH 21/48] Make the Phortune Subscription view show "Deleted Payment Method" for deleted payment methods Summary: Fixes T12224. This brings "Autopay" on the View controller into line with how it works on the Edit controller. Test Plan: - Viewed subscriptions with no autopay, valid autopay, and deleted autopay. {F2750725} Reviewers: chad Reviewed By: chad Maniphest Tasks: T12224 Differential Revision: https://secure.phabricator.com/D17334 --- .../PhortuneSubscriptionViewController.php | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/applications/phortune/controller/PhortuneSubscriptionViewController.php b/src/applications/phortune/controller/PhortuneSubscriptionViewController.php index 0aea396136..daf3daa11d 100644 --- a/src/applications/phortune/controller/PhortuneSubscriptionViewController.php +++ b/src/applications/phortune/controller/PhortuneSubscriptionViewController.php @@ -68,8 +68,23 @@ final class PhortuneSubscriptionViewController extends PhortuneController { $default_method = $subscription->getDefaultPaymentMethodPHID(); if ($default_method) { - $handles = $this->loadViewerHandles(array($default_method)); - $autopay_method = $handles[$default_method]->renderLink(); + $method = id(new PhortunePaymentMethodQuery()) + ->setViewer($viewer) + ->withPHIDs(array($default_method)) + ->withStatuses( + array( + PhortunePaymentMethod::STATUS_ACTIVE, + )) + ->executeOne(); + if ($method) { + $handles = $this->loadViewerHandles(array($default_method)); + $autopay_method = $handles[$default_method]->renderLink(); + } else { + $autopay_method = phutil_tag( + 'em', + array(), + pht('')); + } } else { $autopay_method = phutil_tag( 'em', From 8b2880cfb74950110fc16b4e9b0982673519610c Mon Sep 17 00:00:00 2001 From: Chad Little Date: Sat, 11 Feb 2017 15:30:56 -0800 Subject: [PATCH 22/48] Add a Phurl Typeahead Summary: Adds a basic typeahead for Phurl Objects. Test Plan: http://local.phacility.com/typeahead/browse/PhabricatorPhurlURLDatasource/ Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Differential Revision: https://secure.phabricator.com/D17339 --- src/__phutil_library_map__.php | 2 ++ .../PhabricatorPhurlURLDatasource.php | 35 +++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 src/applications/phurl/typeahead/PhabricatorPhurlURLDatasource.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 01835b98d6..adfd165d4a 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -3371,6 +3371,7 @@ phutil_register_library_map(array( 'PhabricatorPhurlURLAccessController' => 'applications/phurl/controller/PhabricatorPhurlURLAccessController.php', 'PhabricatorPhurlURLCommentController' => 'applications/phurl/controller/PhabricatorPhurlURLCommentController.php', 'PhabricatorPhurlURLCreateCapability' => 'applications/phurl/capability/PhabricatorPhurlURLCreateCapability.php', + 'PhabricatorPhurlURLDatasource' => 'applications/phurl/typeahead/PhabricatorPhurlURLDatasource.php', 'PhabricatorPhurlURLEditConduitAPIMethod' => 'applications/phurl/conduit/PhabricatorPhurlURLEditConduitAPIMethod.php', 'PhabricatorPhurlURLEditController' => 'applications/phurl/controller/PhabricatorPhurlURLEditController.php', 'PhabricatorPhurlURLEditEngine' => 'applications/phurl/editor/PhabricatorPhurlURLEditEngine.php', @@ -8521,6 +8522,7 @@ phutil_register_library_map(array( 'PhabricatorPhurlURLAccessController' => 'PhabricatorPhurlController', 'PhabricatorPhurlURLCommentController' => 'PhabricatorPhurlController', 'PhabricatorPhurlURLCreateCapability' => 'PhabricatorPolicyCapability', + 'PhabricatorPhurlURLDatasource' => 'PhabricatorTypeaheadDatasource', 'PhabricatorPhurlURLEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod', 'PhabricatorPhurlURLEditController' => 'PhabricatorPhurlController', 'PhabricatorPhurlURLEditEngine' => 'PhabricatorEditEngine', diff --git a/src/applications/phurl/typeahead/PhabricatorPhurlURLDatasource.php b/src/applications/phurl/typeahead/PhabricatorPhurlURLDatasource.php new file mode 100644 index 0000000000..cd01c265c8 --- /dev/null +++ b/src/applications/phurl/typeahead/PhabricatorPhurlURLDatasource.php @@ -0,0 +1,35 @@ +executeQuery($query); + $results = array(); + foreach ($urls as $url) { + $result = id(new PhabricatorTypeaheadResult()) + ->setDisplayName($url->getName()) + ->setName($url->getName()." ".$url->getAlias()) + ->setPHID($url->getPHID()) + ->addAttribute($url->getLongURL()); + + $results[] = $result; + } + + return $this->filterResultsAgainstTokens($results); + } + +} From b71e0896693434f2d4e0f20a0e8cf4ae6f371cc9 Mon Sep 17 00:00:00 2001 From: epriestley Date: Mon, 13 Feb 2017 06:17:55 -0800 Subject: [PATCH 23/48] Fix a fatal when viewing methods which no longer exist in the Conduit call log Summary: Fixes T12252. Test Plan: I just faked this, but likely repro is: - Call method `x.y`. - Remove method `x.y` from the codebase. - View log. Reviewers: chad Reviewed By: chad Maniphest Tasks: T12252 Differential Revision: https://secure.phabricator.com/D17342 --- .../conduit/query/PhabricatorConduitLogSearchEngine.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/applications/conduit/query/PhabricatorConduitLogSearchEngine.php b/src/applications/conduit/query/PhabricatorConduitLogSearchEngine.php index 4c91ce7a8d..68f7060507 100644 --- a/src/applications/conduit/query/PhabricatorConduitLogSearchEngine.php +++ b/src/applications/conduit/query/PhabricatorConduitLogSearchEngine.php @@ -162,7 +162,7 @@ final class PhabricatorConduitLogSearchEngine ->addSigil('has-tooltip') ->setMetadata( array( - 'tip' => pht('Unknown ("%s")', $status), + 'tip' => pht('Unknown ("%s")', $method_status), )); break; } From 8dd7b544fe0a52fccf6fa4caf21478ac3dd175f0 Mon Sep 17 00:00:00 2001 From: Austin McKinley Date: Mon, 13 Feb 2017 07:02:11 -0800 Subject: [PATCH 24/48] Don't show an auth provider as enabled if it's still being created Test Plan: attempted to create a new auth provider; observed that "enabled" ui element does not render. viewed existing auth provider and observed that "enabled" ui element still renders Reviewers: #blessed_reviewers, epriestley Reviewed By: #blessed_reviewers, epriestley Subscribers: Korvin Maniphest Tasks: T12245 Differential Revision: https://secure.phabricator.com/D17337 --- .../config/PhabricatorAuthEditController.php | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/applications/auth/controller/config/PhabricatorAuthEditController.php b/src/applications/auth/controller/config/PhabricatorAuthEditController.php index ec2941a3fb..6ff0be4383 100644 --- a/src/applications/auth/controller/config/PhabricatorAuthEditController.php +++ b/src/applications/auth/controller/config/PhabricatorAuthEditController.php @@ -191,16 +191,18 @@ final class PhabricatorAuthEditController ->setHeader(pht('%s: %s', $title, $provider->getProviderName())) ->setHeaderIcon($header_icon); - if ($config->getIsEnabled()) { - $status_name = pht('Enabled'); - $status_color = 'green'; - $status_icon = 'fa-check'; - $header->setStatus($status_icon, $status_color, $status_name); - } else if (!$is_new) { - $status_name = pht('Disabled'); - $status_color = 'indigo'; - $status_icon = 'fa-ban'; - $header->setStatus($status_icon, $status_color, $status_name); + if (!$is_new) { + if ($config->getIsEnabled()) { + $status_name = pht('Enabled'); + $status_color = 'green'; + $status_icon = 'fa-check'; + $header->setStatus($status_icon, $status_color, $status_name); + } else { + $status_name = pht('Disabled'); + $status_color = 'indigo'; + $status_icon = 'fa-ban'; + $header->setStatus($status_icon, $status_color, $status_name); + } } $config_name = 'auth.email-domains'; From 5a850ab23525616ebd6e9c96d7d812ac243c605b Mon Sep 17 00:00:00 2001 From: Chad Little Date: Sat, 11 Feb 2017 19:47:21 -0800 Subject: [PATCH 25/48] Add more information to Dashboard ApplicationSearch list Summary: Fixes T4984. This is about as fancy as I want to get this pass. Adds in the list of panel titles and the author. This does give me a rough idea what's on each dashboard. Test Plan: Visit a list of dashboards and see various authors and panels. {F2810876} Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Maniphest Tasks: T4984 Differential Revision: https://secure.phabricator.com/D17340 --- .../PhabricatorDashboardSearchEngine.php | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/applications/dashboard/query/PhabricatorDashboardSearchEngine.php b/src/applications/dashboard/query/PhabricatorDashboardSearchEngine.php index 56f766c089..6061a0ab8a 100644 --- a/src/applications/dashboard/query/PhabricatorDashboardSearchEngine.php +++ b/src/applications/dashboard/query/PhabricatorDashboardSearchEngine.php @@ -13,7 +13,7 @@ final class PhabricatorDashboardSearchEngine public function newQuery() { return id(new PhabricatorDashboardQuery()) - ->needProjects(true); + ->needPanels(true); } protected function buildCustomSearchFields() { @@ -98,25 +98,22 @@ final class PhabricatorDashboardSearchEngine PhabricatorSavedQuery $query, array $handles) { - $dashboards = mpull($dashboards, null, 'getPHID'); $viewer = $this->requireViewer(); - $proj_phids = array(); + $phids = array(); foreach ($dashboards as $dashboard) { - foreach ($dashboard->getProjectPHIDs() as $project_phid) { - $proj_phids[] = $project_phid; + $author_phid = $dashboard->getAuthorPHID(); + if ($author_phid) { + $phids[] = $author_phid; } } - $proj_handles = id(new PhabricatorHandleQuery()) - ->setViewer($viewer) - ->withPHIDs($proj_phids) - ->execute(); + $handles = $viewer->loadHandles($phids); $list = id(new PHUIObjectItemListView()) ->setUser($viewer); - foreach ($dashboards as $dashboard_phid => $dashboard) { + foreach ($dashboards as $dashboard) { $id = $dashboard->getID(); $item = id(new PHUIObjectItemView()) @@ -125,27 +122,30 @@ final class PhabricatorDashboardSearchEngine ->setHref($this->getApplicationURI("view/{$id}/")) ->setObject($dashboard); - $project_handles = array_select_keys( - $proj_handles, - $dashboard->getProjectPHIDs()); - - $item->addAttribute( - id(new PHUIHandleTagListView()) - ->setLimit(4) - ->setNoDataString(pht('No Projects')) - ->setSlim(true) - ->setHandles($project_handles)); - if ($dashboard->isArchived()) { $item->setDisabled(true); } + $panels = $dashboard->getPanels(); + foreach ($panels as $panel) { + $item->addAttribute($panel->getName()); + } + + if (empty($panels)) { + $empty = phutil_tag('em', array(), pht('No panels.')); + $item->addAttribute($empty); + } + $icon = id(new PHUIIconView()) ->setIcon($dashboard->getIcon()) ->setBackground('bg-dark'); $item->setImageIcon($icon); $item->setEpoch($dashboard->getDateModified()); + $author_phid = $dashboard->getAuthorPHID(); + $author_name = $handles[$author_phid]->renderLink(); + $item->addByline(pht('Author: %s', $author_name)); + $list->addItem($item); } From 554c4f10c5dfce7a95edacd8ddf152ad237d99e3 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Sat, 11 Feb 2017 10:08:47 -0800 Subject: [PATCH 26/48] Remove Copy Dashboard Summary: Ref T10390. This removes the "Copy Dashboard" feature, which was more of a crutch to assist in the complexity of building and maintaining dashboards. I think we're close enough now that removing this and adding in some simpler edit dialogs should negate any benefit to keeping this around. Also removed an un-used "Uninstall Dashboard" dialog. Test Plan: Visit manage, edit, no longer see option to copy dashboard. grep /dashboards/ for "copy" and remove all traces. Add some panels to a dashboard I own. Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Maniphest Tasks: T10390 Differential Revision: https://secure.phabricator.com/D17338 --- src/__phutil_library_map__.php | 4 - .../PhabricatorDashboardApplication.php | 2 - .../PhabricatorDashboardArrangeController.php | 3 +- .../PhabricatorDashboardCopyController.php | 62 --------- .../PhabricatorDashboardManageController.php | 10 +- ...habricatorDashboardPanelEditController.php | 93 ------------- ...habricatorDashboardUninstallController.php | 131 ------------------ .../storage/PhabricatorDashboard.php | 10 -- .../storage/PhabricatorDashboardPanel.php | 13 -- 9 files changed, 2 insertions(+), 326 deletions(-) delete mode 100644 src/applications/dashboard/controller/PhabricatorDashboardCopyController.php delete mode 100644 src/applications/dashboard/controller/PhabricatorDashboardUninstallController.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index adfd165d4a..3c75e7c517 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -2466,7 +2466,6 @@ phutil_register_library_map(array( 'PhabricatorDashboardArchiveController' => 'applications/dashboard/controller/PhabricatorDashboardArchiveController.php', 'PhabricatorDashboardArrangeController' => 'applications/dashboard/controller/PhabricatorDashboardArrangeController.php', 'PhabricatorDashboardController' => 'applications/dashboard/controller/PhabricatorDashboardController.php', - 'PhabricatorDashboardCopyController' => 'applications/dashboard/controller/PhabricatorDashboardCopyController.php', 'PhabricatorDashboardDAO' => 'applications/dashboard/storage/PhabricatorDashboardDAO.php', 'PhabricatorDashboardDashboardHasPanelEdgeType' => 'applications/dashboard/edge/PhabricatorDashboardDashboardHasPanelEdgeType.php', 'PhabricatorDashboardDashboardPHIDType' => 'applications/dashboard/phid/PhabricatorDashboardDashboardPHIDType.php', @@ -2518,7 +2517,6 @@ phutil_register_library_map(array( 'PhabricatorDashboardTransaction' => 'applications/dashboard/storage/PhabricatorDashboardTransaction.php', 'PhabricatorDashboardTransactionEditor' => 'applications/dashboard/editor/PhabricatorDashboardTransactionEditor.php', 'PhabricatorDashboardTransactionQuery' => 'applications/dashboard/query/PhabricatorDashboardTransactionQuery.php', - 'PhabricatorDashboardUninstallController' => 'applications/dashboard/controller/PhabricatorDashboardUninstallController.php', 'PhabricatorDashboardViewController' => 'applications/dashboard/controller/PhabricatorDashboardViewController.php', 'PhabricatorDataCacheSpec' => 'applications/cache/spec/PhabricatorDataCacheSpec.php', 'PhabricatorDataNotAttachedException' => 'infrastructure/storage/lisk/PhabricatorDataNotAttachedException.php', @@ -7476,7 +7474,6 @@ phutil_register_library_map(array( 'PhabricatorDashboardArchiveController' => 'PhabricatorDashboardController', 'PhabricatorDashboardArrangeController' => 'PhabricatorDashboardProfileController', 'PhabricatorDashboardController' => 'PhabricatorController', - 'PhabricatorDashboardCopyController' => 'PhabricatorDashboardController', 'PhabricatorDashboardDAO' => 'PhabricatorLiskDAO', 'PhabricatorDashboardDashboardHasPanelEdgeType' => 'PhabricatorEdgeType', 'PhabricatorDashboardDashboardPHIDType' => 'PhabricatorPHIDType', @@ -7539,7 +7536,6 @@ phutil_register_library_map(array( 'PhabricatorDashboardTransaction' => 'PhabricatorApplicationTransaction', 'PhabricatorDashboardTransactionEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorDashboardTransactionQuery' => 'PhabricatorApplicationTransactionQuery', - 'PhabricatorDashboardUninstallController' => 'PhabricatorDashboardController', 'PhabricatorDashboardViewController' => 'PhabricatorDashboardProfileController', 'PhabricatorDataCacheSpec' => 'PhabricatorCacheSpec', 'PhabricatorDataNotAttachedException' => 'Exception', diff --git a/src/applications/dashboard/application/PhabricatorDashboardApplication.php b/src/applications/dashboard/application/PhabricatorDashboardApplication.php index 8a39cc2a5f..123dcc9f6e 100644 --- a/src/applications/dashboard/application/PhabricatorDashboardApplication.php +++ b/src/applications/dashboard/application/PhabricatorDashboardApplication.php @@ -29,9 +29,7 @@ final class PhabricatorDashboardApplication extends PhabricatorApplication { 'manage/(?P\d+)/' => 'PhabricatorDashboardManageController', 'arrange/(?P\d+)/' => 'PhabricatorDashboardArrangeController', 'create/' => 'PhabricatorDashboardEditController', - 'copy/(?:(?P\d+)/)?' => 'PhabricatorDashboardCopyController', 'edit/(?:(?P\d+)/)?' => 'PhabricatorDashboardEditController', - 'uninstall/(?P\d+)/' => 'PhabricatorDashboardUninstallController', 'addpanel/(?P\d+)/' => 'PhabricatorDashboardAddPanelController', 'movepanel/(?P\d+)/' => 'PhabricatorDashboardMovePanelController', 'removepanel/(?P\d+)/' diff --git a/src/applications/dashboard/controller/PhabricatorDashboardArrangeController.php b/src/applications/dashboard/controller/PhabricatorDashboardArrangeController.php index cc9fb54639..ed8d24d737 100644 --- a/src/applications/dashboard/controller/PhabricatorDashboardArrangeController.php +++ b/src/applications/dashboard/controller/PhabricatorDashboardArrangeController.php @@ -34,8 +34,7 @@ final class PhabricatorDashboardArrangeController $info_view = null; if (!$can_edit) { $no_edit = pht( - 'You do not have permission to edit this dashboard. If you want to '. - 'make changes, make a copy first.'); + 'You do not have permission to edit this dashboard.'); $info_view = id(new PHUIInfoView()) ->setSeverity(PHUIInfoView::SEVERITY_NOTICE) diff --git a/src/applications/dashboard/controller/PhabricatorDashboardCopyController.php b/src/applications/dashboard/controller/PhabricatorDashboardCopyController.php deleted file mode 100644 index a84eb479b5..0000000000 --- a/src/applications/dashboard/controller/PhabricatorDashboardCopyController.php +++ /dev/null @@ -1,62 +0,0 @@ -getViewer(); - $id = $request->getURIData('id'); - - $dashboard = id(new PhabricatorDashboardQuery()) - ->setViewer($viewer) - ->withIDs(array($id)) - ->needPanels(true) - ->executeOne(); - if (!$dashboard) { - return new Aphront404Response(); - } - - $cancel_uri = $this->getApplicationURI('manage/'.$dashboard->getID().'/'); - - if ($request->isFormPost()) { - - $copy = PhabricatorDashboard::initializeNewDashboard($viewer); - $copy = PhabricatorDashboard::copyDashboard($copy, $dashboard); - - $copy->setName(pht('Copy of %s', $copy->getName())); - - // Set up all the edges for the new dashboard. - - $xactions = array(); - $xactions[] = id(new PhabricatorDashboardTransaction()) - ->setTransactionType(PhabricatorTransactions::TYPE_EDGE) - ->setMetadataValue( - 'edge:type', - PhabricatorDashboardDashboardHasPanelEdgeType::EDGECONST) - ->setNewValue( - array( - '=' => array_fuse($dashboard->getPanelPHIDs()), - )); - - $editor = id(new PhabricatorDashboardTransactionEditor()) - ->setActor($viewer) - ->setContentSourceFromRequest($request) - ->setContinueOnMissingFields(true) - ->setContinueOnNoEffect(true) - ->applyTransactions($copy, $xactions); - - $cancel_uri = $this->getApplicationURI('edit/'.$copy->getID().'/'); - return id(new AphrontRedirectResponse())->setURI($cancel_uri); - } - - return $this->newDialog() - ->setTitle(pht('Copy Dashboard')) - ->appendParagraph( - pht( - 'Create a copy of the dashboard "%s"?', - phutil_tag('strong', array(), $dashboard->getName()))) - ->addCancelButton($cancel_uri) - ->addSubmitButton(pht('Create Copy')); - } - -} diff --git a/src/applications/dashboard/controller/PhabricatorDashboardManageController.php b/src/applications/dashboard/controller/PhabricatorDashboardManageController.php index 70027a7332..60b47d6361 100644 --- a/src/applications/dashboard/controller/PhabricatorDashboardManageController.php +++ b/src/applications/dashboard/controller/PhabricatorDashboardManageController.php @@ -47,8 +47,7 @@ final class PhabricatorDashboardManageController $info_view = null; if (!$can_edit) { $no_edit = pht( - 'You do not have permission to edit this dashboard. If you want to '. - 'make changes, make a copy first.'); + 'You do not have permission to edit this dashboard.'); $info_view = id(new PHUIInfoView()) ->setSeverity(PHUIInfoView::SEVERITY_NOTICE) @@ -110,13 +109,6 @@ final class PhabricatorDashboardManageController ->setWorkflow($can_edit)); } - $curtain->addAction( - id(new PhabricatorActionView()) - ->setName(pht('Copy Dashboard')) - ->setIcon('fa-files-o') - ->setHref($this->getApplicationURI("copy/{$id}/")) - ->setWorkflow(true)); - return $curtain; } diff --git a/src/applications/dashboard/controller/PhabricatorDashboardPanelEditController.php b/src/applications/dashboard/controller/PhabricatorDashboardPanelEditController.php index 6ebf0f2eba..7d2f2de5e3 100644 --- a/src/applications/dashboard/controller/PhabricatorDashboardPanelEditController.php +++ b/src/applications/dashboard/controller/PhabricatorDashboardPanelEditController.php @@ -52,25 +52,6 @@ final class PhabricatorDashboardPanelEditController return new Aphront404Response(); } - if ($dashboard) { - $can_edit = PhabricatorPolicyFilter::hasCapability( - $viewer, - $panel, - PhabricatorPolicyCapability::CAN_EDIT); - if (!$can_edit) { - if ($request->isFormPost() && $request->getBool('copy')) { - $panel = $this->copyPanel( - $request, - $dashboard, - $panel); - } else { - return $this->processPanelCloneRequest( - $request, - $dashboard, - $panel); - } - } - } } else { $is_create = true; @@ -365,79 +346,5 @@ final class PhabricatorDashboardPanelEditController ->appendChild($view); } - private function processPanelCloneRequest( - AphrontRequest $request, - PhabricatorDashboard $dashboard, - PhabricatorDashboardPanel $panel) { - - $viewer = $request->getUser(); - - $manage_uri = $this->getApplicationURI('arrange/'.$dashboard->getID().'/'); - - return $this->newDialog() - ->setTitle(pht('Copy Panel?')) - ->addHiddenInput('copy', true) - ->addHiddenInput('dashboardID', $request->getInt('dashboardID')) - ->addHiddenInput('column', $request->getInt('column')) - ->appendParagraph( - pht( - 'You do not have permission to edit this dashboard panel, but you '. - 'can make a copy and edit that instead. If you choose to copy the '. - 'panel, the original will be replaced with the new copy on this '. - 'dashboard.')) - ->appendParagraph( - pht( - 'Do you want to make a copy of this panel?')) - ->addCancelButton($manage_uri) - ->addSubmitButton(pht('Copy Panel')); - } - - private function copyPanel( - AphrontRequest $request, - PhabricatorDashboard $dashboard, - PhabricatorDashboardPanel $panel) { - - $viewer = $request->getUser(); - - $copy = PhabricatorDashboardPanel::initializeNewPanel($viewer); - $copy = PhabricatorDashboardPanel::copyPanel($copy, $panel, $viewer); - - $copy->openTransaction(); - $copy->save(); - - // TODO: This should record a transaction on the panel copy, too. - - $xactions = array(); - $xactions[] = id(new PhabricatorDashboardTransaction()) - ->setTransactionType(PhabricatorTransactions::TYPE_EDGE) - ->setMetadataValue( - 'edge:type', - PhabricatorDashboardDashboardHasPanelEdgeType::EDGECONST) - ->setNewValue( - array( - '+' => array( - $copy->getPHID() => $copy->getPHID(), - ), - '-' => array( - $panel->getPHID() => $panel->getPHID(), - ), - )); - - $layout_config = $dashboard->getLayoutConfigObject(); - $layout_config->replacePanel($panel->getPHID(), $copy->getPHID()); - $dashboard->setLayoutConfigFromObject($layout_config); - $dashboard->save(); - - $editor = id(new PhabricatorDashboardTransactionEditor()) - ->setActor($viewer) - ->setContentSourceFromRequest($request) - ->setContinueOnMissingFields(true) - ->setContinueOnNoEffect(true) - ->applyTransactions($dashboard, $xactions); - $copy->saveTransaction(); - - return $copy; - } - } diff --git a/src/applications/dashboard/controller/PhabricatorDashboardUninstallController.php b/src/applications/dashboard/controller/PhabricatorDashboardUninstallController.php deleted file mode 100644 index fbb0a437fa..0000000000 --- a/src/applications/dashboard/controller/PhabricatorDashboardUninstallController.php +++ /dev/null @@ -1,131 +0,0 @@ -getViewer(); - $id = $request->getURIData('id'); - - $dashboard = id(new PhabricatorDashboardQuery()) - ->setViewer($viewer) - ->withIDs(array($id)) - ->executeOne(); - if (!$dashboard) { - return new Aphront404Response(); - } - $dashboard_phid = $dashboard->getPHID(); - - $object_phid = $request->getStr('objectPHID', $viewer->getPHID()); - $object = id(new PhabricatorObjectQuery()) - ->setViewer($viewer) - ->requireCapabilities( - array( - PhabricatorPolicyCapability::CAN_VIEW, - PhabricatorPolicyCapability::CAN_EDIT, - )) - ->withPHIDs(array($object_phid)) - ->executeOne(); - if (!$object) { - return new Aphront404Response(); - } - - $application_class = $request->getStr( - 'applicationClass', - 'PhabricatorHomeApplication'); - - $dashboard_install = id(new PhabricatorDashboardInstall()) - ->loadOneWhere( - 'objectPHID = %s AND applicationClass = %s', - $object_phid, - $application_class); - if (!$dashboard_install) { - return new Aphront404Response(); - } - if ($dashboard_install->getDashboardPHID() != $dashboard_phid) { - return new Aphront404Response(); - } - - $installer_phid = $viewer->getPHID(); - - if ($request->isFormPost()) { - $dashboard_install->delete(); - return id(new AphrontRedirectResponse()) - ->setURI($this->getRedirectURI($application_class, $object_phid)); - } - - $body = $this->getBodyContent( - $application_class, - $object_phid, - $installer_phid); - - $form = id(new AphrontFormView()) - ->setUser($viewer) - ->appendChild($body); - - return $this->newDialog() - ->setTitle(pht('Uninstall Dashboard')) - ->appendChild($form->buildLayoutView()) - ->addCancelButton($this->getCancelURI( - $application_class, $object_phid, $id)) - ->addSubmitButton(pht('Uninstall Dashboard')); - } - - private function getBodyContent( - $application_class, - $object_phid, - $installer_phid) { - - $viewer = $this->getViewer(); - - $body = array(); - switch ($application_class) { - case 'PhabricatorHomeApplication': - if ($installer_phid == $object_phid) { - $body[] = phutil_tag( - 'p', - array(), - pht( - 'Are you sure you want to uninstall this dashboard as your '. - 'home page?')); - $body[] = phutil_tag( - 'p', - array(), - pht( - 'You will be re-directed to your bland, default home page if '. - 'you choose to uninstall this dashboard.')); - } else { - $body[] = phutil_tag( - 'p', - array(), - pht( - 'Are you sure you want to uninstall this dashboard as the home '. - 'page for %s?', - $viewer->renderHandle($object_phid))); - } - break; - } - return $body; - } - - private function getCancelURI($application_class, $object_phid, $id) { - $uri = null; - switch ($application_class) { - case 'PhabricatorHomeApplication': - $uri = '/dashboard/view/'.$id.'/'; - break; - } - return $uri; - } - - private function getRedirectURI($application_class, $object_phid) { - $uri = null; - switch ($application_class) { - case 'PhabricatorHomeApplication': - $uri = '/'; - break; - } - return $uri; - } - -} diff --git a/src/applications/dashboard/storage/PhabricatorDashboard.php b/src/applications/dashboard/storage/PhabricatorDashboard.php index fb50cba692..325e573715 100644 --- a/src/applications/dashboard/storage/PhabricatorDashboard.php +++ b/src/applications/dashboard/storage/PhabricatorDashboard.php @@ -47,16 +47,6 @@ final class PhabricatorDashboard extends PhabricatorDashboardDAO ); } - public static function copyDashboard( - PhabricatorDashboard $dst, - PhabricatorDashboard $src) { - - $dst->name = $src->name; - $dst->layoutConfig = $src->layoutConfig; - - return $dst; - } - protected function getConfiguration() { return array( self::CONFIG_AUX_PHID => true, diff --git a/src/applications/dashboard/storage/PhabricatorDashboardPanel.php b/src/applications/dashboard/storage/PhabricatorDashboardPanel.php index 7c0c64e18c..4e82aaa348 100644 --- a/src/applications/dashboard/storage/PhabricatorDashboardPanel.php +++ b/src/applications/dashboard/storage/PhabricatorDashboardPanel.php @@ -31,19 +31,6 @@ final class PhabricatorDashboardPanel ->setEditPolicy($actor->getPHID()); } - public static function copyPanel( - PhabricatorDashboardPanel $dst, - PhabricatorDashboardPanel $src, - PhabricatorUser $user) { - - $dst->name = $src->name; - $dst->panelType = $src->panelType; - $dst->properties = $src->properties; - $dst->authorPHID = $user->getPHID(); - - return $dst; - } - protected function getConfiguration() { return array( self::CONFIG_AUX_PHID => true, From 037c749ef33200bf59f0520719eaf1687130e9f2 Mon Sep 17 00:00:00 2001 From: epriestley Date: Mon, 13 Feb 2017 07:39:56 -0800 Subject: [PATCH 27/48] Fix missing setQuoteRef() on Commit detail pages in Diffusion Summary: Fixes T12253. Test Plan: - Before change: used "Quote Comment", saw "In null, alice wrote:" in quoted text. - After change: used "Quote Comment", saw proper reference to the commit/page. Clicked reference, was sent to the comment properly. {F2859093} Reviewers: chad, avivey Reviewed By: avivey Maniphest Tasks: T12253 Differential Revision: https://secure.phabricator.com/D17343 --- .../diffusion/controller/DiffusionCommitController.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/applications/diffusion/controller/DiffusionCommitController.php b/src/applications/diffusion/controller/DiffusionCommitController.php index f8847b7e3b..10677b762f 100644 --- a/src/applications/diffusion/controller/DiffusionCommitController.php +++ b/src/applications/diffusion/controller/DiffusionCommitController.php @@ -705,7 +705,11 @@ final class DiffusionCommitController extends DiffusionController { $timeline = $this->buildTransactionTimeline( $commit, new PhabricatorAuditTransactionQuery()); + $commit->willRenderTimeline($timeline, $this->getRequest()); + + $timeline->setQuoteRef($commit->getMonogram()); + return $timeline; } From 3cf6f746f0555b4d73d587972d896de99667fb06 Mon Sep 17 00:00:00 2001 From: epriestley Date: Mon, 13 Feb 2017 09:45:25 -0800 Subject: [PATCH 28/48] Raise an "Account Setup Issue" if your primary address is unverified Summary: Ref T12237. This adds a UI cue for users who have unverified primary addresses, since we no longer send them mail. Also adds a new `bin/mail unverify` to unverify an address (for example, because mail is bouncing). Test Plan: - Unverified my address, saw setup issue. - Verified my address, no more setup issue. {F2861820} Reviewers: chad Reviewed By: chad Maniphest Tasks: T12237 Differential Revision: https://secure.phabricator.com/D17344 --- src/__phutil_library_map__.php | 4 + ...bricatorMailManagementUnverifyWorkflow.php | 110 ++++++++++++++++++ .../PhabricatorSettingsApplication.php | 1 + .../PhabricatorSettingsIssueController.php | 103 ++++++++++++++++ .../page/menu/PhabricatorMainMenuView.php | 65 +++++++++++ 5 files changed, 283 insertions(+) create mode 100644 src/applications/metamta/management/PhabricatorMailManagementUnverifyWorkflow.php create mode 100644 src/applications/settings/controller/PhabricatorSettingsIssueController.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 3c75e7c517..5e9a0c23be 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -2947,6 +2947,7 @@ phutil_register_library_map(array( 'PhabricatorMailManagementSendTestWorkflow' => 'applications/metamta/management/PhabricatorMailManagementSendTestWorkflow.php', 'PhabricatorMailManagementShowInboundWorkflow' => 'applications/metamta/management/PhabricatorMailManagementShowInboundWorkflow.php', 'PhabricatorMailManagementShowOutboundWorkflow' => 'applications/metamta/management/PhabricatorMailManagementShowOutboundWorkflow.php', + 'PhabricatorMailManagementUnverifyWorkflow' => 'applications/metamta/management/PhabricatorMailManagementUnverifyWorkflow.php', 'PhabricatorMailManagementVolumeWorkflow' => 'applications/metamta/management/PhabricatorMailManagementVolumeWorkflow.php', 'PhabricatorMailManagementWorkflow' => 'applications/metamta/management/PhabricatorMailManagementWorkflow.php', 'PhabricatorMailOutboundMailHeraldAdapter' => 'applications/metamta/herald/PhabricatorMailOutboundMailHeraldAdapter.php', @@ -3772,6 +3773,7 @@ phutil_register_library_map(array( 'PhabricatorSettingsDeveloperPanelGroup' => 'applications/settings/panelgroup/PhabricatorSettingsDeveloperPanelGroup.php', 'PhabricatorSettingsEditEngine' => 'applications/settings/editor/PhabricatorSettingsEditEngine.php', 'PhabricatorSettingsEmailPanelGroup' => 'applications/settings/panelgroup/PhabricatorSettingsEmailPanelGroup.php', + 'PhabricatorSettingsIssueController' => 'applications/settings/controller/PhabricatorSettingsIssueController.php', 'PhabricatorSettingsListController' => 'applications/settings/controller/PhabricatorSettingsListController.php', 'PhabricatorSettingsLogsPanelGroup' => 'applications/settings/panelgroup/PhabricatorSettingsLogsPanelGroup.php', 'PhabricatorSettingsMainController' => 'applications/settings/controller/PhabricatorSettingsMainController.php', @@ -8009,6 +8011,7 @@ phutil_register_library_map(array( 'PhabricatorMailManagementSendTestWorkflow' => 'PhabricatorMailManagementWorkflow', 'PhabricatorMailManagementShowInboundWorkflow' => 'PhabricatorMailManagementWorkflow', 'PhabricatorMailManagementShowOutboundWorkflow' => 'PhabricatorMailManagementWorkflow', + 'PhabricatorMailManagementUnverifyWorkflow' => 'PhabricatorMailManagementWorkflow', 'PhabricatorMailManagementVolumeWorkflow' => 'PhabricatorMailManagementWorkflow', 'PhabricatorMailManagementWorkflow' => 'PhabricatorManagementWorkflow', 'PhabricatorMailOutboundMailHeraldAdapter' => 'HeraldAdapter', @@ -9021,6 +9024,7 @@ phutil_register_library_map(array( 'PhabricatorSettingsDeveloperPanelGroup' => 'PhabricatorSettingsPanelGroup', 'PhabricatorSettingsEditEngine' => 'PhabricatorEditEngine', 'PhabricatorSettingsEmailPanelGroup' => 'PhabricatorSettingsPanelGroup', + 'PhabricatorSettingsIssueController' => 'PhabricatorController', 'PhabricatorSettingsListController' => 'PhabricatorController', 'PhabricatorSettingsLogsPanelGroup' => 'PhabricatorSettingsPanelGroup', 'PhabricatorSettingsMainController' => 'PhabricatorController', diff --git a/src/applications/metamta/management/PhabricatorMailManagementUnverifyWorkflow.php b/src/applications/metamta/management/PhabricatorMailManagementUnverifyWorkflow.php new file mode 100644 index 0000000000..61861d1db0 --- /dev/null +++ b/src/applications/metamta/management/PhabricatorMailManagementUnverifyWorkflow.php @@ -0,0 +1,110 @@ +setName('unverify') + ->setSynopsis( + pht('Unverify an email address so it no longer receives mail.')) + ->setExamples('**unverify** __address__ ...') + ->setArguments( + array( + array( + 'name' => 'addresses', + 'wildcard' => true, + 'help' => pht('Address (or addresses) to unverify.'), + ), + )); + } + + public function execute(PhutilArgumentParser $args) { + $console = PhutilConsole::getConsole(); + $viewer = $this->getViewer(); + + $addresses = $args->getArg('addresses'); + if (!$addresses) { + throw new PhutilArgumentUsageException( + pht('Specify one or more email addresses to unverify.')); + } + + foreach ($addresses as $address) { + $email = id(new PhabricatorUserEmail())->loadOneWhere( + 'address = %s', + $address); + if (!$email) { + echo tsprintf( + "%s\n", + pht( + 'Address "%s" is unknown.', + $address)); + continue; + } + + $user_phid = $email->getUserPHID(); + + $user = id(new PhabricatorPeopleQuery()) + ->setViewer($viewer) + ->withPHIDs(array($user_phid)) + ->executeOne(); + + if (!$user) { + echo tsprintf( + "%s\n", + pht( + 'Address "%s" belongs to invalid user "%s".', + $address, + $user_phid)); + continue; + } + + if (!$email->getIsVerified()) { + echo tsprintf( + "%s\n", + pht( + 'Address "%s" (owned by "%s") is already unveriifed.', + $address, + $user->getUsername())); + continue; + } + + $email->openTransaction(); + + $email + ->setIsVerified(0) + ->save(); + + if ($email->getIsPrimary()) { + $user + ->setIsEmailVerified(0) + ->save(); + } + + $email->saveTransaction(); + + if ($email->getIsPrimary()) { + echo tsprintf( + "%s\n", + pht( + 'Unverified "%s", the primary address for "%s".', + $address, + $user->getUsername())); + } else { + echo tsprintf( + "%s\n", + pht( + 'Unverified "%s", an address for "%s".', + $address, + $user->getUsername())); + } + } + + echo tsprintf( + "%s\n", + pht('Done.')); + + return 0; + } + +} diff --git a/src/applications/settings/application/PhabricatorSettingsApplication.php b/src/applications/settings/application/PhabricatorSettingsApplication.php index 45a694fb59..d5add43d46 100644 --- a/src/applications/settings/application/PhabricatorSettingsApplication.php +++ b/src/applications/settings/application/PhabricatorSettingsApplication.php @@ -41,6 +41,7 @@ final class PhabricatorSettingsApplication extends PhabricatorApplication { 'adjust/' => 'PhabricatorSettingsAdjustController', 'timezone/(?P[^/]+)/' => 'PhabricatorSettingsTimezoneController', + 'issue/' => 'PhabricatorSettingsIssueController', ), ); } diff --git a/src/applications/settings/controller/PhabricatorSettingsIssueController.php b/src/applications/settings/controller/PhabricatorSettingsIssueController.php new file mode 100644 index 0000000000..bb472c8832 --- /dev/null +++ b/src/applications/settings/controller/PhabricatorSettingsIssueController.php @@ -0,0 +1,103 @@ +getViewer(); + + $setup_uri = id(new PhabricatorEmailAddressesSettingsPanel()) + ->setViewer($viewer) + ->setUser($viewer) + ->getPanelURI(); + + $issues = array(); + if (!$viewer->getIsEmailVerified()) { + // We could specifically detect that the user has missed email because + // their address is unverified here and point them at Mail so they can + // look at messages they missed. + + // We could also detect that an administrator unverified their address + // and let that come with a message. + + // For now, just make sure the unverified address does not escape notice. + $issues[] = array( + 'title' => pht('Primary Email Unverified'), + 'summary' => pht( + 'Your primary email address is unverified. You will not be able '. + 'to receive email until you verify it.'), + 'uri' => $setup_uri, + ); + } + + if ($issues) { + require_celerity_resource('phabricator-notification-menu-css'); + + $items = array(); + foreach ($issues as $issue) { + $classes = array(); + $classes[] = 'phabricator-notification'; + $classes[] = 'phabricator-notification-unread'; + + $uri = $issue['uri']; + $title = $issue['title']; + $summary = $issue['summary']; + + $items[] = javelin_tag( + 'div', + array( + 'class' => + 'phabricator-notification phabricator-notification-unread', + 'sigil' => 'notification', + 'meta' => array( + 'href' => $uri, + ), + ), + array( + phutil_tag('strong', array(), pht('%s:', $title)), + ' ', + $summary, + )); + } + + $content = phutil_tag( + 'div', + array( + 'class' => 'setup-issue-menu', + ), + $items); + } else { + $content = phutil_tag( + 'div', + array( + 'class' => 'phabricator-notification no-notifications', + ), + pht('You have no account setup issues.')); + } + + $header = phutil_tag( + 'div', + array( + 'class' => 'phabricator-notification-header', + ), + phutil_tag( + 'a', + array( + 'href' => $setup_uri, + ), + pht('Account Setup Issues'))); + + $content = array( + $header, + $content, + ); + + $json = array( + 'content' => hsprintf('%s', $content), + 'number' => count($issues), + ); + + return id(new AphrontAjaxResponse())->setContent($json); + } + +} diff --git a/src/view/page/menu/PhabricatorMainMenuView.php b/src/view/page/menu/PhabricatorMainMenuView.php index e923a5e348..f9e4032d87 100644 --- a/src/view/page/menu/PhabricatorMainMenuView.php +++ b/src/view/page/menu/PhabricatorMainMenuView.php @@ -595,10 +595,74 @@ final class PhabricatorMainMenuView extends AphrontView { } } + $user_dropdown = null; + $user_tag = null; + if ($viewer->isLoggedIn()) { + if (!$viewer->getIsEmailVerified()) { + $bubble_id = celerity_generate_unique_node_id(); + $count_id = celerity_generate_unique_node_id(); + $dropdown_id = celerity_generate_unique_node_id(); + + $settings_uri = id(new PhabricatorEmailAddressesSettingsPanel()) + ->setViewer($viewer) + ->setUser($viewer) + ->getPanelURI(); + + $user_icon = javelin_tag( + 'span', + array( + 'class' => 'phabricator-main-menu-setup-icon phui-icon-view '. + 'phui-font-fa fa-user', + 'sigil' => 'menu-icon', + )); + + $user_count = javelin_tag( + 'span', + array( + 'class' => 'phabricator-main-menu-setup-count', + 'id' => $count_id, + ), + 1); + + $user_tag = phutil_tag( + 'a', + array( + 'href' => $settings_uri, + 'class' => 'setup-unread', + 'id' => $bubble_id, + ), + array( + $user_icon, + $user_count, + )); + + Javelin::initBehavior( + 'aphlict-dropdown', + array( + 'bubbleID' => $bubble_id, + 'countID' => $count_id, + 'dropdownID' => $dropdown_id, + 'loadingText' => pht('Loading...'), + 'uri' => '/settings/issue/', + 'unreadClass' => 'setup-unread', + )); + + $user_dropdown = javelin_tag( + 'div', + array( + 'id' => $dropdown_id, + 'class' => 'phabricator-notification-menu', + 'sigil' => 'phabricator-notification-menu', + 'style' => 'display: none;', + )); + } + } + $dropdowns = array( $notification_dropdown, $message_notification_dropdown, $setup_notification_dropdown, + $user_dropdown, ); return array( @@ -606,6 +670,7 @@ final class PhabricatorMainMenuView extends AphrontView { $bubble_tag, $message_tag, $setup_tag, + $user_tag, ), $dropdowns, $aural, From 006d74fde20c14c4c676f8b20e842f249edbf056 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Mon, 13 Feb 2017 11:10:27 -0800 Subject: [PATCH 29/48] Clean up some search result alignment CSS Summary: Aligns the search result list to the right of the input box, adds a little space, removes a double border. Test Plan: Search on desktop, mobile, tablet breakpoints. Double check normal typeahead results. Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Differential Revision: https://secure.phabricator.com/D17345 --- resources/celerity/map.php | 16 ++++++++-------- webroot/rsrc/css/aphront/typeahead.css | 5 ++++- .../rsrc/css/application/base/main-menu-view.css | 7 +++---- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/resources/celerity/map.php b/resources/celerity/map.php index fd063fd5cb..245e810cd8 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -9,7 +9,7 @@ return array( 'names' => array( 'conpherence.pkg.css' => 'a520d619', 'conpherence.pkg.js' => '6249a1cf', - 'core.pkg.css' => '76a0e8c9', + 'core.pkg.css' => '1179d101', 'core.pkg.js' => '1fa7c0c5', 'darkconsole.pkg.js' => 'e7393ebb', 'differential.pkg.css' => '4815647b', @@ -31,10 +31,10 @@ return array( 'rsrc/css/aphront/tokenizer.css' => '9a8cb501', 'rsrc/css/aphront/tooltip.css' => '173b9431', 'rsrc/css/aphront/typeahead-browse.css' => '8904346a', - 'rsrc/css/aphront/typeahead.css' => 'd4f16145', + 'rsrc/css/aphront/typeahead.css' => '8a84cc7d', 'rsrc/css/application/almanac/almanac.css' => 'dbb9b3af', 'rsrc/css/application/auth/auth.css' => '0877ed6e', - 'rsrc/css/application/base/main-menu-view.css' => '43d59288', + 'rsrc/css/application/base/main-menu-view.css' => '5294060f', 'rsrc/css/application/base/notification-menu.css' => '6a697e43', 'rsrc/css/application/base/phui-theme.css' => '9f261c6b', 'rsrc/css/application/base/standard-page-view.css' => '894d8a25', @@ -555,7 +555,7 @@ return array( 'aphront-table-view-css' => '6ca8e057', 'aphront-tokenizer-control-css' => '9a8cb501', 'aphront-tooltip-css' => '173b9431', - 'aphront-typeahead-control-css' => 'd4f16145', + 'aphront-typeahead-control-css' => '8a84cc7d', 'application-search-view-css' => '66ee5d46', 'auth-css' => '0877ed6e', 'bulk-job-css' => 'df9c1d4a', @@ -797,7 +797,7 @@ return array( 'phabricator-flag-css' => 'bba8f811', 'phabricator-keyboard-shortcut' => '1ae869f2', 'phabricator-keyboard-shortcut-manager' => '4a021c10', - 'phabricator-main-menu-view' => '43d59288', + 'phabricator-main-menu-view' => '5294060f', 'phabricator-nav-view-css' => 'e58a4a30', 'phabricator-notification' => 'ccf1cbf8', 'phabricator-notification-css' => '3f6c89c9', @@ -1171,9 +1171,6 @@ return array( 'javelin-dom', 'javelin-request', ), - '43d59288' => array( - 'phui-theme-css', - ), '44959b73' => array( 'javelin-util', 'javelin-uri', @@ -1280,6 +1277,9 @@ return array( 'javelin-vector', 'javelin-typeahead-static-source', ), + '5294060f' => array( + 'phui-theme-css', + ), '5359e785' => array( 'javelin-install', 'javelin-util', diff --git a/webroot/rsrc/css/aphront/typeahead.css b/webroot/rsrc/css/aphront/typeahead.css index 0f63918e40..bdda2703e0 100644 --- a/webroot/rsrc/css/aphront/typeahead.css +++ b/webroot/rsrc/css/aphront/typeahead.css @@ -4,7 +4,7 @@ div.jx-typeahead-hardpoint { position: relative; - _zoom: 1; /* Some kind of IE6 fix? */ /* yes */ /* why? */ + _zoom: 1; /* Some kind of IE6 fix? */ /* yes */ /* why? */ /* still need? */ } div.jx-typeahead-results { @@ -28,6 +28,9 @@ div.jx-typeahead-results a.jx-result { color: {$darkgreytext}; display: block; font-size: {$normalfontsize}; +} + +div.jx-typeahead-results a.jx-result + a.jx-result { border-top: 1px solid {$hoverborder}; } diff --git a/webroot/rsrc/css/application/base/main-menu-view.css b/webroot/rsrc/css/application/base/main-menu-view.css index 0860909382..28148ae71a 100644 --- a/webroot/rsrc/css/application/base/main-menu-view.css +++ b/webroot/rsrc/css/application/base/main-menu-view.css @@ -139,8 +139,7 @@ } .device-desktop .phabricator-main-menu-search-target { - width: 320px; - margin-left: -150px; + width: 360px; } .device .phabricator-main-menu-search-target { @@ -276,11 +275,11 @@ a.phabricator-core-user-menu .caret:before { box-shadow: {$dropshadow}; border: 1px solid {$lightgreyborder}; border-radius: 3px; - margin-left: 40px; + margin-left: -64px; } .device .phabricator-main-menu-search-target div.jx-typeahead-results { - margin-left: 30px; + margin-left: 28px; } .phabricator-main-search-typeahead-result .phabricator-search-icon { From 6f37685a75894668992b3dc09446dda3d6a29d9f Mon Sep 17 00:00:00 2001 From: epriestley Date: Mon, 13 Feb 2017 13:06:03 -0800 Subject: [PATCH 30/48] Fix flipped open/closed status for Diviner atoms in search index Summary: Fixes T12258. I think these constants are just flipped. Test Plan: Kinda winged it. Reviewers: chad Reviewed By: chad Maniphest Tasks: T12258 Differential Revision: https://secure.phabricator.com/D17346 --- .../diviner/search/DivinerLiveSymbolFulltextEngine.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/applications/diviner/search/DivinerLiveSymbolFulltextEngine.php b/src/applications/diviner/search/DivinerLiveSymbolFulltextEngine.php index 694af0a27b..80f3e0c026 100644 --- a/src/applications/diviner/search/DivinerLiveSymbolFulltextEngine.php +++ b/src/applications/diviner/search/DivinerLiveSymbolFulltextEngine.php @@ -33,8 +33,8 @@ final class DivinerLiveSymbolFulltextEngine $document->addRelationship( $atom->getGraphHash() - ? PhabricatorSearchRelationship::RELATIONSHIP_CLOSED - : PhabricatorSearchRelationship::RELATIONSHIP_OPEN, + ? PhabricatorSearchRelationship::RELATIONSHIP_OPEN + : PhabricatorSearchRelationship::RELATIONSHIP_CLOSED, $atom->getBookPHID(), DivinerBookPHIDType::TYPECONST, PhabricatorTime::getNow()); From f9163bf06539d8c885941e0c5f794a8d9895c74f Mon Sep 17 00:00:00 2001 From: Chad Little Date: Mon, 13 Feb 2017 13:46:39 -0800 Subject: [PATCH 31/48] Allow lightbox comments to be viewed logged out Summary: Fixes T12160. Lightbox thread view should be visible if file is public. Test Plan: Add a file to a task, log out, click on file in task, get lightbox and no error. Expand comments, see login box. {F2867067} {F2867088} {F2867098} {F2867114} {F2867124} Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Maniphest Tasks: T12160 Differential Revision: https://secure.phabricator.com/D17347 --- .../files/controller/PhabricatorFileLightboxController.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/applications/files/controller/PhabricatorFileLightboxController.php b/src/applications/files/controller/PhabricatorFileLightboxController.php index e57d977786..11d4b95bc1 100644 --- a/src/applications/files/controller/PhabricatorFileLightboxController.php +++ b/src/applications/files/controller/PhabricatorFileLightboxController.php @@ -3,6 +3,10 @@ final class PhabricatorFileLightboxController extends PhabricatorFileController { + public function shouldAllowPublic() { + return true; + } + public function handleRequest(AphrontRequest $request) { $viewer = $request->getViewer(); $phid = $request->getURIData('phid'); From 1cb924ce68ba2f67b8b1871123a6fe71b3aa4f11 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Tue, 14 Feb 2017 02:52:29 +0000 Subject: [PATCH 32/48] Fix duplicating panel when editing in column 2 Summary: Fixes T10612. We're writing a new panel to any dashboard even if it already exists. No need when just updating a panel title. Test Plan: Add "welcome" panel to column 2 of a clean dashboard. Edit title, save. See correct panel in correct place. Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Maniphest Tasks: T10612 Differential Revision: https://secure.phabricator.com/D17349 --- .../controller/PhabricatorDashboardPanelEditController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/applications/dashboard/controller/PhabricatorDashboardPanelEditController.php b/src/applications/dashboard/controller/PhabricatorDashboardPanelEditController.php index 7d2f2de5e3..cc7502afef 100644 --- a/src/applications/dashboard/controller/PhabricatorDashboardPanelEditController.php +++ b/src/applications/dashboard/controller/PhabricatorDashboardPanelEditController.php @@ -143,7 +143,7 @@ final class PhabricatorDashboardPanelEditController ->applyTransactions($panel, $xactions); // If we're creating a panel directly on a dashboard, add it now. - if ($dashboard) { + if ($dashboard && $is_create) { PhabricatorDashboardTransactionEditor::addPanelToDashboard( $viewer, PhabricatorContentSource::newFromRequest($request), From 2c09fc56051b925c0634e5a15b5246e6c756bc74 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Mon, 13 Feb 2017 16:30:33 -0800 Subject: [PATCH 33/48] Make Panels slightly easier to find and use Summary: Ref T10390, turns "add existing panel" into a typeahead, and add lots more information to search. Test Plan: Add an existing panel, click the search icon, see more information (type, engine). Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Maniphest Tasks: T10390 Differential Revision: https://secure.phabricator.com/D17348 --- ...PhabricatorDashboardAddPanelController.php | 19 +++++-------- .../PhabricatorDashboardPanelType.php | 1 + .../PhabricatorDashboardQueryPanelType.php | 4 +++ .../PhabricatorDashboardTabsPanelType.php | 4 +++ .../PhabricatorDashboardTextPanelType.php | 4 +++ .../PhabricatorDashboardPanelDatasource.php | 27 ++++++++++++++++--- 6 files changed, 42 insertions(+), 17 deletions(-) diff --git a/src/applications/dashboard/controller/PhabricatorDashboardAddPanelController.php b/src/applications/dashboard/controller/PhabricatorDashboardAddPanelController.php index f34bdd06ae..46712d79e9 100644 --- a/src/applications/dashboard/controller/PhabricatorDashboardAddPanelController.php +++ b/src/applications/dashboard/controller/PhabricatorDashboardAddPanelController.php @@ -23,7 +23,7 @@ final class PhabricatorDashboardAddPanelController $redirect_uri = $this->getApplicationURI( 'arrange/'.$dashboard->getID().'/'); - $v_panel = $request->getStr('panel'); + $v_panel = head($request->getArr('panel')); $e_panel = true; $errors = array(); if ($request->isFormPost()) { @@ -70,26 +70,19 @@ final class PhabricatorDashboardAddPanelController ->addCancelButton($redirect_uri); } - $panel_options = array(); - foreach ($panels as $panel) { - $panel_options[$panel->getID()] = pht( - '%s %s', - $panel->getMonogram(), - $panel->getName()); - } - $form = id(new AphrontFormView()) ->setUser($viewer) ->addHiddenInput('column', $request->getInt('column')) ->appendRemarkupInstructions( pht('Choose a panel to add to this dashboard:')) ->appendChild( - id(new AphrontFormSelectControl()) + id(new AphrontFormTokenizerControl()) + ->setUser($this->getViewer()) + ->setDatasource(new PhabricatorDashboardPanelDatasource()) + ->setLimit(1) ->setName('panel') ->setLabel(pht('Panel')) - ->setValue($v_panel) - ->setError($e_panel) - ->setOptions($panel_options)); + ->setValue($v_panel)); return $this->newDialog() ->setTitle(pht('Add Panel')) diff --git a/src/applications/dashboard/paneltype/PhabricatorDashboardPanelType.php b/src/applications/dashboard/paneltype/PhabricatorDashboardPanelType.php index 81e7ec80cc..34c7b1c3ee 100644 --- a/src/applications/dashboard/paneltype/PhabricatorDashboardPanelType.php +++ b/src/applications/dashboard/paneltype/PhabricatorDashboardPanelType.php @@ -6,6 +6,7 @@ abstract class PhabricatorDashboardPanelType extends Phobject { abstract public function getPanelTypeName(); abstract public function getPanelTypeDescription(); abstract public function getFieldSpecifications(); + abstract public function getIcon(); abstract public function renderPanelContent( PhabricatorUser $viewer, diff --git a/src/applications/dashboard/paneltype/PhabricatorDashboardQueryPanelType.php b/src/applications/dashboard/paneltype/PhabricatorDashboardQueryPanelType.php index 76e6e8432b..0781d71b16 100644 --- a/src/applications/dashboard/paneltype/PhabricatorDashboardQueryPanelType.php +++ b/src/applications/dashboard/paneltype/PhabricatorDashboardQueryPanelType.php @@ -11,6 +11,10 @@ final class PhabricatorDashboardQueryPanelType return pht('Query Panel'); } + public function getIcon() { + return 'fa-search'; + } + public function getPanelTypeDescription() { return pht( 'Show results of a search query, like the most recently filed tasks or '. diff --git a/src/applications/dashboard/paneltype/PhabricatorDashboardTabsPanelType.php b/src/applications/dashboard/paneltype/PhabricatorDashboardTabsPanelType.php index 3cb758a11a..292446fe55 100644 --- a/src/applications/dashboard/paneltype/PhabricatorDashboardTabsPanelType.php +++ b/src/applications/dashboard/paneltype/PhabricatorDashboardTabsPanelType.php @@ -11,6 +11,10 @@ final class PhabricatorDashboardTabsPanelType return pht('Tab Panel'); } + public function getIcon() { + return 'fa-window-maximize'; + } + public function getPanelTypeDescription() { return pht('Use tabs to switch between several other panels.'); } diff --git a/src/applications/dashboard/paneltype/PhabricatorDashboardTextPanelType.php b/src/applications/dashboard/paneltype/PhabricatorDashboardTextPanelType.php index 413d3dc856..5ecde8501f 100644 --- a/src/applications/dashboard/paneltype/PhabricatorDashboardTextPanelType.php +++ b/src/applications/dashboard/paneltype/PhabricatorDashboardTextPanelType.php @@ -11,6 +11,10 @@ final class PhabricatorDashboardTextPanelType return pht('Text Panel'); } + public function getIcon() { + return 'fa-paragraph'; + } + public function getPanelTypeDescription() { return pht( 'Add some static text to the dashboard. This can be used to '. diff --git a/src/applications/dashboard/typeahead/PhabricatorDashboardPanelDatasource.php b/src/applications/dashboard/typeahead/PhabricatorDashboardPanelDatasource.php index 35c8c5c212..958883d34e 100644 --- a/src/applications/dashboard/typeahead/PhabricatorDashboardPanelDatasource.php +++ b/src/applications/dashboard/typeahead/PhabricatorDashboardPanelDatasource.php @@ -16,9 +16,19 @@ final class PhabricatorDashboardPanelDatasource } public function loadResults() { - $query = id(new PhabricatorDashboardPanelQuery()); + $results = $this->buildResults(); + return $this->filterResultsAgainstTokens($results); + } + + protected function renderSpecialTokens(array $values) { + return $this->renderTokensFromResults($this->buildResults(), $values); + } + + public function buildResults() { + $query = id(new PhabricatorDashboardPanelQuery()); $panels = $this->executeQuery($query); + $results = array(); foreach ($panels as $panel) { $impl = $panel->getImplementation(); @@ -27,20 +37,29 @@ final class PhabricatorDashboardPanelDatasource } else { $type_text = nonempty($panel->getPanelType(), pht('Unknown Type')); } + $id = $panel->getID(); + $monogram = $panel->getMonogram(); + $properties = $panel->getProperties(); $result = id(new PhabricatorTypeaheadResult()) ->setName($panel->getName()) - ->setPHID($panel->getPHID()) + ->setDisplayName($monogram.' '.$panel->getName()) + ->setPHID($id) + ->setIcon($impl->getIcon()) ->addAttribute($type_text); + if (!empty($properties['class'])) { + $result->addAttribute($properties['class']); + } + if ($panel->getIsArchived()) { $result->setClosed(pht('Archived')); } - $results[] = $result; + $results[$id] = $result; } - return $this->filterResultsAgainstTokens($results); + return $results; } } From 128a9d13fc0a5085c296b558ab92815c59ce84a5 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Mon, 13 Feb 2017 21:06:01 -0800 Subject: [PATCH 34/48] Fix diviner documenation hover states Summary: Bump up the CSS scope, since we altered the normal rule for device-desktop Test Plan: /diviner/ in sandbox Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Differential Revision: https://secure.phabricator.com/D17352 --- resources/celerity/map.php | 4 ++-- webroot/rsrc/css/diviner/diviner-shared.css | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/resources/celerity/map.php b/resources/celerity/map.php index 245e810cd8..469dc9eb02 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -111,7 +111,7 @@ return array( 'rsrc/css/core/remarkup.css' => '4a2de2bb', 'rsrc/css/core/syntax.css' => '769d3498', 'rsrc/css/core/z-index.css' => '5e72c4e0', - 'rsrc/css/diviner/diviner-shared.css' => 'aa3656aa', + 'rsrc/css/diviner/diviner-shared.css' => '896f1d43', 'rsrc/css/font/font-aleo.css' => '8bdb2835', 'rsrc/css/font/font-awesome.css' => 'e838e088', 'rsrc/css/font/font-lato.css' => 'c7ccd872', @@ -583,7 +583,7 @@ return array( 'diffusion-icons-css' => 'd678600a', 'diffusion-readme-css' => '297373eb', 'diffusion-source-css' => '750add59', - 'diviner-shared-css' => 'aa3656aa', + 'diviner-shared-css' => '896f1d43', 'font-aleo' => '8bdb2835', 'font-fontawesome' => 'e838e088', 'font-lato' => 'c7ccd872', diff --git a/webroot/rsrc/css/diviner/diviner-shared.css b/webroot/rsrc/css/diviner/diviner-shared.css index 67a09616f7..56dc6ddf30 100644 --- a/webroot/rsrc/css/diviner/diviner-shared.css +++ b/webroot/rsrc/css/diviner/diviner-shared.css @@ -172,7 +172,7 @@ body .diviner-view .diviner-section-content .phui-header-shell { margin: 4px -16px; } -.diviner-book-item:hover { +a.diviner-book-item:hover { text-decoration: none; } From 5556f0e45a52d8d5f48fb6be8c1a8b427c7cc6ac Mon Sep 17 00:00:00 2001 From: Chad Little Date: Mon, 13 Feb 2017 20:31:50 -0800 Subject: [PATCH 35/48] Don't allow duplicate panels on dashboards Summary: Fixes T10145. I went with "don't add two panels", since panels are easy to create, I expect this to be a reasonable limit until we have better use cases. Test Plan: Try to add the same panel twice, get error. Add panel normally fine, move panels fine, edit panels fine. Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Maniphest Tasks: T10145 Differential Revision: https://secure.phabricator.com/D17351 --- .../PhabricatorDashboardAddPanelController.php | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/applications/dashboard/controller/PhabricatorDashboardAddPanelController.php b/src/applications/dashboard/controller/PhabricatorDashboardAddPanelController.php index 46712d79e9..65560f624f 100644 --- a/src/applications/dashboard/controller/PhabricatorDashboardAddPanelController.php +++ b/src/applications/dashboard/controller/PhabricatorDashboardAddPanelController.php @@ -10,6 +10,7 @@ final class PhabricatorDashboardAddPanelController $dashboard = id(new PhabricatorDashboardQuery()) ->setViewer($viewer) ->withIDs(array($id)) + ->needPanels(true) ->requireCapabilities( array( PhabricatorPolicyCapability::CAN_VIEW, @@ -33,9 +34,18 @@ final class PhabricatorDashboardAddPanelController ->withIDs(array($v_panel)) ->executeOne(); if (!$panel) { - $errors[] = pht('No such panel!'); + $errors[] = pht('Not a valid panel.'); $e_panel = pht('Invalid'); } + + $on_dashboard = $dashboard->getPanels(); + $on_ids = mpull($on_dashboard, null, 'getID'); + if (array_key_exists($v_panel, $on_ids)) { + $p_name = $panel->getName(); + $errors[] = pht('Panel "%s" already exists on dashboard.', $p_name); + $e_panel = pht('Invalid'); + } + } else { $errors[] = pht('Select a panel to add.'); $e_panel = pht('Required'); @@ -81,8 +91,7 @@ final class PhabricatorDashboardAddPanelController ->setDatasource(new PhabricatorDashboardPanelDatasource()) ->setLimit(1) ->setName('panel') - ->setLabel(pht('Panel')) - ->setValue($v_panel)); + ->setLabel(pht('Panel'))); return $this->newDialog() ->setTitle(pht('Add Panel')) From b28b2b8ab87c46ffab1e6fe88c65603c55322c5c Mon Sep 17 00:00:00 2001 From: Chad Little Date: Tue, 14 Feb 2017 13:29:55 -0800 Subject: [PATCH 36/48] Use typeahead for tab panel selection Summary: Fixes T11449. Feels.... magical? Probably a more efficient way of doing this, but only 6 tabs so... Test Plan: Create a tab panel in old UI. Edit panel in new UI. Create a panel in new UI, edit panel in new UI. Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Maniphest Tasks: T11449 Differential Revision: https://secure.phabricator.com/D17355 --- ...abricatorDashboardPanelTabsCustomField.php | 34 ++++++++----------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/src/applications/dashboard/customfield/PhabricatorDashboardPanelTabsCustomField.php b/src/applications/dashboard/customfield/PhabricatorDashboardPanelTabsCustomField.php index f473b3f6cd..c1088cbdd3 100644 --- a/src/applications/dashboard/customfield/PhabricatorDashboardPanelTabsCustomField.php +++ b/src/applications/dashboard/customfield/PhabricatorDashboardPanelTabsCustomField.php @@ -15,7 +15,11 @@ final class PhabricatorDashboardPanelTabsCustomField $value = array(); $names = $request->getArr($this->getFieldKey().'_name'); - $panels = $request->getArr($this->getFieldKey().'_panelID'); + $panel_ids = $request->getArr($this->getFieldKey().'_panelID'); + $panels = array(); + foreach ($panel_ids as $panel_id) { + $panels[] = $panel_id[0]; + } foreach ($names as $idx => $name) { $panel_id = idx($panels, $idx); if (strlen($name) && $panel_id) { @@ -34,21 +38,6 @@ final class PhabricatorDashboardPanelTabsCustomField // when saving a tab panel that includes archied panels. This whole UI is // hopefully temporary anyway. - $panels = id(new PhabricatorDashboardPanelQuery()) - ->setViewer($this->getViewer()) - ->execute(); - - $panel_map = array(); - foreach ($panels as $panel) { - $panel_map[$panel->getID()] = pht( - '%s %s', - $panel->getMonogram(), - $panel->getName()); - } - $panel_map = array( - '' => pht('(None)'), - ) + $panel_map; - $value = $this->getFieldValue(); if (!is_array($value)) { $value = array(); @@ -57,15 +46,22 @@ final class PhabricatorDashboardPanelTabsCustomField $out = array(); for ($ii = 1; $ii <= 6; $ii++) { $tab = idx($value, ($ii - 1), array()); + $panel = idx($tab, 'panelID', null); + $panel_id = array(); + if ($panel) { + $panel_id[] = $panel; + } $out[] = id(new AphrontFormTextControl()) ->setName($this->getFieldKey().'_name[]') ->setValue(idx($tab, 'name')) ->setLabel(pht('Tab %d Name', $ii)); - $out[] = id(new AphrontFormSelectControl()) + $out[] = id(new AphrontFormTokenizerControl()) + ->setUser($this->getViewer()) + ->setDatasource(new PhabricatorDashboardPanelDatasource()) ->setName($this->getFieldKey().'_panelID[]') - ->setValue(idx($tab, 'panelID')) - ->setOptions($panel_map) + ->setValue($panel_id) + ->setLimit(1) ->setLabel(pht('Tab %d Panel', $ii)); } From 37ac0ada178c70179036b6047d6ff7ffd1849da8 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Tue, 14 Feb 2017 14:08:56 -0800 Subject: [PATCH 37/48] Restrict movable panels to non-tab panels Summary: Fixes T12248. Adds a flag for movable panels, and only allows those to be moved. Also cleaned up some CSS rules missing once a panel was drug into a new position. Test Plan: Try to drag a tab panel content pane, cannot. Drag normal pane, see CSS, grab and drag same panel back, CSS looks the same. Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Maniphest Tasks: T12248 Differential Revision: https://secure.phabricator.com/D17356 --- resources/celerity/map.php | 26 +++++++++---------- ...abricatorDashboardPanelRenderingEngine.php | 15 +++++++++++ .../PhabricatorDashboardTabsPanelType.php | 1 + .../css/application/dashboard/dashboard.css | 12 ++++----- .../behavior-dashboard-move-panels.js | 2 +- 5 files changed, 36 insertions(+), 20 deletions(-) diff --git a/resources/celerity/map.php b/resources/celerity/map.php index 469dc9eb02..d2953c72dd 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -9,7 +9,7 @@ return array( 'names' => array( 'conpherence.pkg.css' => 'a520d619', 'conpherence.pkg.js' => '6249a1cf', - 'core.pkg.css' => '1179d101', + 'core.pkg.css' => '0d7ecd3b', 'core.pkg.js' => '1fa7c0c5', 'darkconsole.pkg.js' => 'e7393ebb', 'differential.pkg.css' => '4815647b', @@ -55,7 +55,7 @@ return array( 'rsrc/css/application/contentsource/content-source-view.css' => '4b8b05d4', 'rsrc/css/application/countdown/timer.css' => '16c52f5c', 'rsrc/css/application/daemon/bulk-job.css' => 'df9c1d4a', - 'rsrc/css/application/dashboard/dashboard.css' => '005e064e', + 'rsrc/css/application/dashboard/dashboard.css' => '0921c307', 'rsrc/css/application/diff/inline-comment-summary.css' => '51efda3a', 'rsrc/css/application/differential/add-comment.css' => 'c47f8c40', 'rsrc/css/application/differential/changeset-view.css' => '6a9bdf9c', @@ -392,7 +392,7 @@ return array( 'rsrc/js/application/countdown/timer.js' => 'e4cc26b3', 'rsrc/js/application/daemon/behavior-bulk-job-reload.js' => 'edf8a145', 'rsrc/js/application/dashboard/behavior-dashboard-async-panel.js' => '469c0d9e', - 'rsrc/js/application/dashboard/behavior-dashboard-move-panels.js' => '019f36c4', + 'rsrc/js/application/dashboard/behavior-dashboard-move-panels.js' => '408bf173', 'rsrc/js/application/dashboard/behavior-dashboard-query-panel-select.js' => '453c5375', 'rsrc/js/application/dashboard/behavior-dashboard-tab-panel.js' => 'd4eecc63', 'rsrc/js/application/diff/behavior-preview-link.js' => '051c7832', @@ -617,7 +617,7 @@ return array( 'javelin-behavior-countdown-timer' => 'e4cc26b3', 'javelin-behavior-dark-console' => 'f411b6ae', 'javelin-behavior-dashboard-async-panel' => '469c0d9e', - 'javelin-behavior-dashboard-move-panels' => '019f36c4', + 'javelin-behavior-dashboard-move-panels' => '408bf173', 'javelin-behavior-dashboard-query-panel-select' => '453c5375', 'javelin-behavior-dashboard-tab-panel' => 'd4eecc63', 'javelin-behavior-day-view' => '4b3c4443', @@ -786,7 +786,7 @@ return array( 'phabricator-content-source-view-css' => '4b8b05d4', 'phabricator-core-css' => '9f4cb463', 'phabricator-countdown-css' => '16c52f5c', - 'phabricator-dashboard-css' => '005e064e', + 'phabricator-dashboard-css' => '0921c307', 'phabricator-drag-and-drop-file-upload' => '58dea2fa', 'phabricator-draggable-list' => 'bea6e7f4', 'phabricator-fatal-config-template-css' => '8f18fa41', @@ -927,14 +927,6 @@ return array( 'javelin-request', 'javelin-typeahead-source', ), - '019f36c4' => array( - 'javelin-behavior', - 'javelin-dom', - 'javelin-util', - 'javelin-stratcom', - 'javelin-workflow', - 'phabricator-draggable-list', - ), '01fca1f0' => array( 'javelin-behavior', 'javelin-workflow', @@ -1161,6 +1153,14 @@ return array( 'javelin-workflow', 'javelin-stratcom', ), + '408bf173' => array( + 'javelin-behavior', + 'javelin-dom', + 'javelin-util', + 'javelin-stratcom', + 'javelin-workflow', + 'phabricator-draggable-list', + ), '40a6a403' => array( 'javelin-install', 'javelin-dom', diff --git a/src/applications/dashboard/engine/PhabricatorDashboardPanelRenderingEngine.php b/src/applications/dashboard/engine/PhabricatorDashboardPanelRenderingEngine.php index fbd5aaa2bb..26aa24cb0c 100644 --- a/src/applications/dashboard/engine/PhabricatorDashboardPanelRenderingEngine.php +++ b/src/applications/dashboard/engine/PhabricatorDashboardPanelRenderingEngine.php @@ -13,6 +13,7 @@ final class PhabricatorDashboardPanelRenderingEngine extends Phobject { private $parentPanelPHIDs; private $headerMode = self::HEADER_MODE_NORMAL; private $dashboardID; + private $movable = true; public function setDashboardID($id) { $this->dashboardID = $id; @@ -63,6 +64,15 @@ final class PhabricatorDashboardPanelRenderingEngine extends Phobject { return $this; } + public function setMovable($movable) { + $this->movable = $movable; + return $this; + } + + public function getMovable() { + return $this->movable; + } + public function getPanel() { return $this->panel; } @@ -221,8 +231,13 @@ final class PhabricatorDashboardPanelRenderingEngine extends Phobject { $box ->setHeader($header) ->setID($id) + ->addClass('dashboard-box') ->addSigil('dashboard-panel'); + if ($this->getMovable()) { + $box->addSigil('panel-movable'); + } + if ($panel) { $box->setMetadata( array( diff --git a/src/applications/dashboard/paneltype/PhabricatorDashboardTabsPanelType.php b/src/applications/dashboard/paneltype/PhabricatorDashboardTabsPanelType.php index 292446fe55..b4772ba83f 100644 --- a/src/applications/dashboard/paneltype/PhabricatorDashboardTabsPanelType.php +++ b/src/applications/dashboard/paneltype/PhabricatorDashboardTabsPanelType.php @@ -97,6 +97,7 @@ final class PhabricatorDashboardTabsPanelType ->setPanel($panel) ->setPanelPHID($panel->getPHID()) ->setHeaderMode($no_headers) + ->setMovable(false) ->renderPanel(); } else { $panel_content = pht('(Invalid Panel)'); diff --git a/webroot/rsrc/css/application/dashboard/dashboard.css b/webroot/rsrc/css/application/dashboard/dashboard.css index 8bce842053..037dd227df 100644 --- a/webroot/rsrc/css/application/dashboard/dashboard.css +++ b/webroot/rsrc/css/application/dashboard/dashboard.css @@ -14,12 +14,12 @@ margin: 0 0 16px 0; } -.dashboard-view .phui-header-shell { +.dashboard-box .phui-header-shell { padding-top: 4px; padding-bottom: 16px; } -.dashboard-view .phui-header-header { +.dashboard-box .phui-header-header { color: #000; } @@ -49,16 +49,16 @@ width: 66.66%; } -.grippable .aphront-multi-column-column .dashboard-pane .phui-object-box { +.grippable .aphront-multi-column-column .dashboard-box.phui-object-box { cursor: move; } -.grippable .aphront-multi-column-column .dashboard-pane .phui-object-box:hover { +.grippable .aphront-multi-column-column .dashboard-box.phui-object-box:hover { box-shadow: {$dropshadow}; } -.grippable .aphront-multi-column-column .dashboard-pane .phui-object-box:hover - .phui-object-box { +.grippable .aphront-multi-column-column .dashboard-box.phui-object-box:hover + .dashboard-box { box-shadow: none; } diff --git a/webroot/rsrc/js/application/dashboard/behavior-dashboard-move-panels.js b/webroot/rsrc/js/application/dashboard/behavior-dashboard-move-panels.js index fbbf411be8..d8d08eca5f 100644 --- a/webroot/rsrc/js/application/dashboard/behavior-dashboard-move-panels.js +++ b/webroot/rsrc/js/application/dashboard/behavior-dashboard-move-panels.js @@ -10,7 +10,7 @@ JX.behavior('dashboard-move-panels', function(config) { - var itemSigil = 'dashboard-panel'; + var itemSigil = 'panel-movable'; function finditems(col) { return JX.DOM.scry(col, 'div', itemSigil); From 2f69cb5fe75a2ab409feed179c196583f021ec4e Mon Sep 17 00:00:00 2001 From: Chad Little Date: Wed, 15 Feb 2017 11:05:26 -0800 Subject: [PATCH 38/48] Add more transation data to panel tab changes Summary: Fixes T10473. Clever, didn't know we could do this, but works well. Renders out the tab names by ', '. Test Plan: Add a tab panel, change some names, review transactions. {F2929594} Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Maniphest Tasks: T10473 Differential Revision: https://secure.phabricator.com/D17359 --- ...abricatorDashboardPanelTabsCustomField.php | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/applications/dashboard/customfield/PhabricatorDashboardPanelTabsCustomField.php b/src/applications/dashboard/customfield/PhabricatorDashboardPanelTabsCustomField.php index c1088cbdd3..96566db54a 100644 --- a/src/applications/dashboard/customfield/PhabricatorDashboardPanelTabsCustomField.php +++ b/src/applications/dashboard/customfield/PhabricatorDashboardPanelTabsCustomField.php @@ -33,6 +33,49 @@ final class PhabricatorDashboardPanelTabsCustomField $this->setFieldValue($value); } + public function getApplicationTransactionTitle( + PhabricatorApplicationTransaction $xaction) { + $author_phid = $xaction->getAuthorPHID(); + $old = $xaction->getOldValue(); + $new = $xaction->getNewValue(); + + $new_tabs = array(); + if ($new) { + foreach ($new as $new_tab) { + $new_tabs[] = $new_tab['name']; + } + $new_tabs = implode(' | ', $new_tabs); + } + + $old_tabs = array(); + if ($old) { + foreach ($old as $old_tab) { + $old_tabs[] = $old_tab['name']; + } + $old_tabs = implode(' | ', $old_tabs); + } + + if (!$old) { + // In case someone makes a tab panel with no tabs. + if ($new) { + return pht( + '%s set the tabs to "%s".', + $xaction->renderHandleLink($author_phid), + $new_tabs); + } + } else if (!$new) { + return pht( + '%s removed tabs.', + $xaction->renderHandleLink($author_phid)); + } else { + return pht( + '%s changed the tabs from "%s" to "%s".', + $xaction->renderHandleLink($author_phid), + $old_tabs, + $new_tabs); + } + } + public function renderEditControl(array $handles) { // NOTE: This includes archived panels so we don't mutate the tabs // when saving a tab panel that includes archied panels. This whole UI is From 9716e83d605f4352bec788e8e224178875d7fb8b Mon Sep 17 00:00:00 2001 From: Chad Little Date: Wed, 15 Feb 2017 11:32:08 -0800 Subject: [PATCH 39/48] Build Badges View page into more of a profile Summary: Ref T10798. Cleans up the UI a little and adds a sidenav. Test Plan: Review badge and recipients in sandbox. Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Maniphest Tasks: T10798 Differential Revision: https://secure.phabricator.com/D17358 --- src/__phutil_library_map__.php | 7 +- .../PhabricatorBadgesApplication.php | 13 +-- ...bricatorBadgesEditRecipientsController.php | 6 +- .../PhabricatorBadgesProfileController.php | 88 +++++++++++++++++++ .../PhabricatorBadgesRecipientsController.php | 58 ++++++++++++ .../PhabricatorBadgesViewController.php | 42 ++------- .../badges/storage/PhabricatorBadgesBadge.php | 9 -- .../storage/PhabricatorBadgesTransaction.php | 4 + .../PhabricatorBadgesRecipientsListView.php | 14 ++- 9 files changed, 187 insertions(+), 54 deletions(-) create mode 100644 src/applications/badges/controller/PhabricatorBadgesProfileController.php create mode 100644 src/applications/badges/controller/PhabricatorBadgesRecipientsController.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 5e9a0c23be..c8b3f97726 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -2027,8 +2027,10 @@ phutil_register_library_map(array( 'PhabricatorBadgesListController' => 'applications/badges/controller/PhabricatorBadgesListController.php', 'PhabricatorBadgesMailReceiver' => 'applications/badges/mail/PhabricatorBadgesMailReceiver.php', 'PhabricatorBadgesPHIDType' => 'applications/badges/phid/PhabricatorBadgesPHIDType.php', + 'PhabricatorBadgesProfileController' => 'applications/badges/controller/PhabricatorBadgesProfileController.php', 'PhabricatorBadgesQuality' => 'applications/badges/constants/PhabricatorBadgesQuality.php', 'PhabricatorBadgesQuery' => 'applications/badges/query/PhabricatorBadgesQuery.php', + 'PhabricatorBadgesRecipientsController' => 'applications/badges/controller/PhabricatorBadgesRecipientsController.php', 'PhabricatorBadgesRecipientsListView' => 'applications/badges/view/PhabricatorBadgesRecipientsListView.php', 'PhabricatorBadgesRemoveRecipientsController' => 'applications/badges/controller/PhabricatorBadgesRemoveRecipientsController.php', 'PhabricatorBadgesReplyHandler' => 'applications/badges/mail/PhabricatorBadgesReplyHandler.php', @@ -6942,7 +6944,6 @@ phutil_register_library_map(array( 'PhabricatorPolicyInterface', 'PhabricatorApplicationTransactionInterface', 'PhabricatorSubscribableInterface', - 'PhabricatorTokenReceiverInterface', 'PhabricatorFlaggableInterface', 'PhabricatorDestructibleInterface', 'PhabricatorConduitResultInterface', @@ -6964,8 +6965,10 @@ phutil_register_library_map(array( 'PhabricatorBadgesListController' => 'PhabricatorBadgesController', 'PhabricatorBadgesMailReceiver' => 'PhabricatorObjectMailReceiver', 'PhabricatorBadgesPHIDType' => 'PhabricatorPHIDType', + 'PhabricatorBadgesProfileController' => 'PhabricatorController', 'PhabricatorBadgesQuality' => 'Phobject', 'PhabricatorBadgesQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', + 'PhabricatorBadgesRecipientsController' => 'PhabricatorBadgesProfileController', 'PhabricatorBadgesRecipientsListView' => 'AphrontView', 'PhabricatorBadgesRemoveRecipientsController' => 'PhabricatorBadgesController', 'PhabricatorBadgesReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler', @@ -6975,7 +6978,7 @@ phutil_register_library_map(array( 'PhabricatorBadgesTransaction' => 'PhabricatorApplicationTransaction', 'PhabricatorBadgesTransactionComment' => 'PhabricatorApplicationTransactionComment', 'PhabricatorBadgesTransactionQuery' => 'PhabricatorApplicationTransactionQuery', - 'PhabricatorBadgesViewController' => 'PhabricatorBadgesController', + 'PhabricatorBadgesViewController' => 'PhabricatorBadgesProfileController', 'PhabricatorBarePageUIExample' => 'PhabricatorUIExample', 'PhabricatorBarePageView' => 'AphrontPageView', 'PhabricatorBaseURISetupCheck' => 'PhabricatorSetupCheck', diff --git a/src/applications/badges/application/PhabricatorBadgesApplication.php b/src/applications/badges/application/PhabricatorBadgesApplication.php index ce52eff99a..6eab0c55f8 100644 --- a/src/applications/badges/application/PhabricatorBadgesApplication.php +++ b/src/applications/badges/application/PhabricatorBadgesApplication.php @@ -47,11 +47,14 @@ final class PhabricatorBadgesApplication extends PhabricatorApplication { => 'PhabricatorBadgesArchiveController', 'view/(?:(?P\d+)/)?' => 'PhabricatorBadgesViewController', - 'recipients/(?P[1-9]\d*)/' - => 'PhabricatorBadgesEditRecipientsController', - 'recipients/(?P[1-9]\d*)/remove/' - => 'PhabricatorBadgesRemoveRecipientsController', - + 'recipients/' => array( + '(?P[1-9]\d*)/' + => 'PhabricatorBadgesRecipientsController', + '(?P[1-9]\d*)/add/' + => 'PhabricatorBadgesEditRecipientsController', + '(?P[1-9]\d*)/remove/' + => 'PhabricatorBadgesRemoveRecipientsController', + ), ), ); } diff --git a/src/applications/badges/controller/PhabricatorBadgesEditRecipientsController.php b/src/applications/badges/controller/PhabricatorBadgesEditRecipientsController.php index a73c6777af..2f794e4470 100644 --- a/src/applications/badges/controller/PhabricatorBadgesEditRecipientsController.php +++ b/src/applications/badges/controller/PhabricatorBadgesEditRecipientsController.php @@ -22,7 +22,7 @@ final class PhabricatorBadgesEditRecipientsController return new Aphront404Response(); } - $view_uri = $this->getApplicationURI('view/'.$badge->getID().'/'); + $view_uri = $this->getApplicationURI('recipients/'.$badge->getID().'/'); $awards = $badge->getAwards(); $recipient_phids = mpull($awards, 'getRecipientPHID'); @@ -79,13 +79,13 @@ final class PhabricatorBadgesEditRecipientsController ->appendControl( id(new AphrontFormTokenizerControl()) ->setName('phids') - ->setLabel(pht('Add Recipients')) + ->setLabel(pht('Recipients')) ->setDatasource(new PhabricatorPeopleDatasource())); } $dialog = id(new AphrontDialogView()) ->setUser($viewer) - ->setTitle(pht('Award Badges')) + ->setTitle(pht('Add Recipients')) ->appendForm($form) ->addCancelButton($view_uri) ->addSubmitButton(pht('Add Recipients')); diff --git a/src/applications/badges/controller/PhabricatorBadgesProfileController.php b/src/applications/badges/controller/PhabricatorBadgesProfileController.php new file mode 100644 index 0000000000..97d4b11b93 --- /dev/null +++ b/src/applications/badges/controller/PhabricatorBadgesProfileController.php @@ -0,0 +1,88 @@ +badge = $badge; + return $this; + } + + public function getBadge() { + return $this->badge; + } + + public function buildApplicationMenu() { + return $this->buildSideNavView()->getMenu(); + } + + protected function buildHeaderView() { + $viewer = $this->getViewer(); + $badge = $this->getBadge(); + $id = $badge->getID(); + + if ($badge->isArchived()) { + $status_icon = 'fa-ban'; + $status_color = 'dark'; + } else { + $status_icon = 'fa-check'; + $status_color = 'bluegrey'; + } + $status_name = idx( + PhabricatorBadgesBadge::getStatusNameMap(), + $badge->getStatus()); + + return id(new PHUIHeaderView()) + ->setHeader($badge->getName()) + ->setUser($viewer) + ->setPolicyObject($badge) + ->setStatus($status_icon, $status_color, $status_name) + ->setHeaderIcon('fa-trophy'); + } + + protected function buildApplicationCrumbs() { + $badge = $this->getBadge(); + $id = $badge->getID(); + $badge_uri = $this->getApplicationURI("/view/{$id}/"); + + $crumbs = parent::buildApplicationCrumbs(); + $crumbs->addTextCrumb($badge->getName(), $badge_uri); + $crumbs->setBorder(true); + return $crumbs; + } + + protected function buildSideNavView($filter = null) { + $viewer = $this->getViewer(); + $badge = $this->getBadge(); + $id = $badge->getID(); + + $can_edit = PhabricatorPolicyFilter::hasCapability( + $viewer, + $badge, + PhabricatorPolicyCapability::CAN_EDIT); + + $nav = id(new AphrontSideNavFilterView()) + ->setBaseURI(new PhutilURI($this->getApplicationURI())); + + $nav->addLabel(pht('Badge')); + + $nav->addFilter( + 'view', + pht('View Badge'), + $this->getApplicationURI("/view/{$id}/"), + 'fa-trophy'); + + $nav->addFilter( + 'recipients', + pht('View Recipients'), + $this->getApplicationURI("/recipients/{$id}/"), + 'fa-group'); + + $nav->selectFilter($filter); + + return $nav; + } + +} diff --git a/src/applications/badges/controller/PhabricatorBadgesRecipientsController.php b/src/applications/badges/controller/PhabricatorBadgesRecipientsController.php new file mode 100644 index 0000000000..2b6bb6b10a --- /dev/null +++ b/src/applications/badges/controller/PhabricatorBadgesRecipientsController.php @@ -0,0 +1,58 @@ +getViewer(); + $id = $request->getURIData('id'); + + $badge = id(new PhabricatorBadgesQuery()) + ->setViewer($viewer) + ->withIDs(array($id)) + ->needRecipients(true) + ->executeOne(); + if (!$badge) { + return new Aphront404Response(); + } + + $this->setBadge($badge); + + $crumbs = $this->buildApplicationCrumbs(); + $crumbs->addTextCrumb(pht('Recipients')); + $crumbs->setBorder(true); + $title = $badge->getName(); + + $header = $this->buildHeaderView(); + + $awards = $badge->getAwards(); + $recipient_phids = mpull($awards, 'getRecipientPHID'); + $recipient_phids = array_reverse($recipient_phids); + $handles = $this->loadViewerHandles($recipient_phids); + + $recipient_list = id(new PhabricatorBadgesRecipientsListView()) + ->setBadge($badge) + ->setHandles($handles) + ->setUser($viewer); + + $view = id(new PHUITwoColumnView()) + ->setHeader($header) + ->setFooter(array( + $recipient_list, + )); + + $navigation = $this->buildSideNavView('recipients'); + + return $this->newPage() + ->setTitle($title) + ->setCrumbs($crumbs) + ->setPageObjectPHIDs(array($badge->getPHID())) + ->setNavigation($navigation) + ->appendChild($view); + } + +} diff --git a/src/applications/badges/controller/PhabricatorBadgesViewController.php b/src/applications/badges/controller/PhabricatorBadgesViewController.php index 05f6286020..3c434ff1d5 100644 --- a/src/applications/badges/controller/PhabricatorBadgesViewController.php +++ b/src/applications/badges/controller/PhabricatorBadgesViewController.php @@ -1,7 +1,7 @@ setViewer($viewer) ->withIDs(array($id)) - ->needRecipients(true) ->executeOne(); if (!$badge) { return new Aphront404Response(); } + $this->setBadge($badge); + $crumbs = $this->buildApplicationCrumbs(); - $crumbs->addTextCrumb($badge->getName()); - $crumbs->setBorder(true); $title = $badge->getName(); - if ($badge->isArchived()) { - $status_icon = 'fa-ban'; - $status_color = 'dark'; - } else { - $status_icon = 'fa-check'; - $status_color = 'bluegrey'; - } - $status_name = idx( - PhabricatorBadgesBadge::getStatusNameMap(), - $badge->getStatus()); - - $header = id(new PHUIHeaderView()) - ->setHeader($badge->getName()) - ->setUser($viewer) - ->setPolicyObject($badge) - ->setStatus($status_icon, $status_color, $status_name) - ->setHeaderIcon('fa-trophy'); - + $header = $this->buildHeaderView(); $curtain = $this->buildCurtain($badge); $details = $this->buildDetailsView($badge); @@ -50,16 +32,6 @@ final class PhabricatorBadgesViewController $badge, new PhabricatorBadgesTransactionQuery()); - $awards = $badge->getAwards(); - $recipient_phids = mpull($awards, 'getRecipientPHID'); - $recipient_phids = array_reverse($recipient_phids); - $handles = $this->loadViewerHandles($recipient_phids); - - $recipient_list = id(new PhabricatorBadgesRecipientsListView()) - ->setBadge($badge) - ->setHandles($handles) - ->setUser($viewer); - $comment_view = id(new PhabricatorBadgesEditEngine()) ->setViewer($viewer) ->buildEditEngineCommentView($badge); @@ -68,16 +40,18 @@ final class PhabricatorBadgesViewController ->setHeader($header) ->setCurtain($curtain) ->setMainColumn(array( - $recipient_list, $timeline, $comment_view, )) ->addPropertySection(pht('Description'), $details); + $navigation = $this->buildSideNavView('view'); + return $this->newPage() ->setTitle($title) ->setCrumbs($crumbs) ->setPageObjectPHIDs(array($badge->getPHID())) + ->setNavigation($navigation) ->appendChild($view); } @@ -116,7 +90,7 @@ final class PhabricatorBadgesViewController $id = $badge->getID(); $edit_uri = $this->getApplicationURI("/edit/{$id}/"); $archive_uri = $this->getApplicationURI("/archive/{$id}/"); - $award_uri = $this->getApplicationURI("/recipients/{$id}/"); + $award_uri = $this->getApplicationURI("/recipients/{$id}/add/"); $curtain = $this->newCurtainView($badge); diff --git a/src/applications/badges/storage/PhabricatorBadgesBadge.php b/src/applications/badges/storage/PhabricatorBadgesBadge.php index d14d49a57c..4cdc4edf61 100644 --- a/src/applications/badges/storage/PhabricatorBadgesBadge.php +++ b/src/applications/badges/storage/PhabricatorBadgesBadge.php @@ -5,7 +5,6 @@ final class PhabricatorBadgesBadge extends PhabricatorBadgesDAO PhabricatorPolicyInterface, PhabricatorApplicationTransactionInterface, PhabricatorSubscribableInterface, - PhabricatorTokenReceiverInterface, PhabricatorFlaggableInterface, PhabricatorDestructibleInterface, PhabricatorConduitResultInterface, @@ -161,14 +160,6 @@ final class PhabricatorBadgesBadge extends PhabricatorBadgesDAO } -/* -( PhabricatorTokenReceiverInterface )---------------------------------- */ - - - public function getUsersToNotifyOfTokenGiven() { - return array($this->getCreatorPHID()); - } - - /* -( PhabricatorDestructibleInterface )----------------------------------- */ diff --git a/src/applications/badges/storage/PhabricatorBadgesTransaction.php b/src/applications/badges/storage/PhabricatorBadgesTransaction.php index 22505b247e..24509f94bb 100644 --- a/src/applications/badges/storage/PhabricatorBadgesTransaction.php +++ b/src/applications/badges/storage/PhabricatorBadgesTransaction.php @@ -38,6 +38,10 @@ final class PhabricatorBadgesTransaction $type = $this->getTransactionType(); switch ($type) { + case PhabricatorTransactions::TYPE_CREATE: + return pht( + '%s created this badge.', + $this->renderHandleLink($author_phid)); case self::TYPE_NAME: if ($old === null) { return pht( diff --git a/src/applications/badges/view/PhabricatorBadgesRecipientsListView.php b/src/applications/badges/view/PhabricatorBadgesRecipientsListView.php index c5d3a56cda..f221487ed2 100644 --- a/src/applications/badges/view/PhabricatorBadgesRecipientsListView.php +++ b/src/applications/badges/view/PhabricatorBadgesRecipientsListView.php @@ -27,6 +27,18 @@ final class PhabricatorBadgesRecipientsListView extends AphrontView { $badge, PhabricatorPolicyCapability::CAN_EDIT); + $award_button = id(new PHUIButtonView()) + ->setTag('a') + ->setIcon('fa-plus') + ->setText(pht('Add Recipents')) + ->setWorkflow(true) + ->setDisabled(!$can_edit) + ->setHref('/badges/recipients/'.$badge->getID().'/add/'); + + $header = id(new PHUIHeaderView()) + ->setHeader(pht('Recipients')) + ->addActionLink($award_button); + $list = id(new PHUIObjectItemListView()) ->setNoDataString(pht('This badge does not have any recipients.')) ->setFlush(true); @@ -62,7 +74,7 @@ final class PhabricatorBadgesRecipientsListView extends AphrontView { } $box = id(new PHUIObjectBoxView()) - ->setHeaderText(pht('Recipients')) + ->setHeader($header) ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) ->setObjectList($list); From e0cd3062d5abce25bf40754f7eac588011abffaf Mon Sep 17 00:00:00 2001 From: Chad Little Date: Wed, 15 Feb 2017 12:59:02 -0800 Subject: [PATCH 40/48] Restrict all crumbs to 240 max width Summary: Ref T12270. Any project, badge, dashboard, etc, that uses names in crumbs can over generate a long title. Restrict to a sane but generous width. Test Plan: Make a project with a really long name, test various crumb layouts, boards, tasks, desktop, mobile. Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Maniphest Tasks: T12270 Differential Revision: https://secure.phabricator.com/D17361 --- resources/celerity/map.php | 6 +++--- webroot/rsrc/css/phui/phui-crumbs-view.css | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/resources/celerity/map.php b/resources/celerity/map.php index d2953c72dd..be48409185 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -9,7 +9,7 @@ return array( 'names' => array( 'conpherence.pkg.css' => 'a520d619', 'conpherence.pkg.js' => '6249a1cf', - 'core.pkg.css' => '0d7ecd3b', + 'core.pkg.css' => 'dbd1023f', 'core.pkg.js' => '1fa7c0c5', 'darkconsole.pkg.js' => 'e7393ebb', 'differential.pkg.css' => '4815647b', @@ -139,7 +139,7 @@ return array( 'rsrc/css/phui/phui-cms.css' => '504b4b23', 'rsrc/css/phui/phui-comment-form.css' => '48fbd65d', 'rsrc/css/phui/phui-comment-panel.css' => 'f50152ad', - 'rsrc/css/phui/phui-crumbs-view.css' => 'b743f73e', + 'rsrc/css/phui/phui-crumbs-view.css' => '6ece3bbb', 'rsrc/css/phui/phui-curtain-view.css' => '947bf1a4', 'rsrc/css/phui/phui-document-pro.css' => 'f56738ed', 'rsrc/css/phui/phui-document-summary.css' => '9ca48bdf', @@ -850,7 +850,7 @@ return array( 'phui-cms-css' => '504b4b23', 'phui-comment-form-css' => '48fbd65d', 'phui-comment-panel-css' => 'f50152ad', - 'phui-crumbs-view-css' => 'b743f73e', + 'phui-crumbs-view-css' => '6ece3bbb', 'phui-curtain-view-css' => '947bf1a4', 'phui-document-summary-view-css' => '9ca48bdf', 'phui-document-view-css' => 'c32e8dec', diff --git a/webroot/rsrc/css/phui/phui-crumbs-view.css b/webroot/rsrc/css/phui/phui-crumbs-view.css index d2d0744819..6155e9b2b8 100644 --- a/webroot/rsrc/css/phui/phui-crumbs-view.css +++ b/webroot/rsrc/css/phui/phui-crumbs-view.css @@ -48,6 +48,10 @@ .phui-crumb-view { float: left; padding: 8px 0; + max-width: 240px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; } .device-phone .phui-crumb-view.phabricator-last-crumb .phui-crumb-name, From 01f277cef22c5473296c9b4cf021eba816a748dc Mon Sep 17 00:00:00 2001 From: epriestley Date: Thu, 16 Feb 2017 06:18:23 -0800 Subject: [PATCH 41/48] Fix a CalendarExport issue when an existing export has an unsupported mode Summary: See D16676. When an export has an unsupported mode (bad database value, out-of-date object, etc) the intent of this code is to put it into the `