diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 033e7c15d2..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', @@ -2464,8 +2466,8 @@ 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', 'PhabricatorDashboardDashboardHasPanelEdgeType' => 'applications/dashboard/edge/PhabricatorDashboardDashboardHasPanelEdgeType.php', 'PhabricatorDashboardDashboardPHIDType' => 'applications/dashboard/phid/PhabricatorDashboardDashboardPHIDType.php', @@ -2503,6 +2505,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', @@ -2516,7 +2519,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', @@ -2947,6 +2949,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', @@ -3029,6 +3032,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', @@ -3368,6 +3372,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', @@ -3770,6 +3775,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', @@ -6938,7 +6944,6 @@ phutil_register_library_map(array( 'PhabricatorPolicyInterface', 'PhabricatorApplicationTransactionInterface', 'PhabricatorSubscribableInterface', - 'PhabricatorTokenReceiverInterface', 'PhabricatorFlaggableInterface', 'PhabricatorDestructibleInterface', 'PhabricatorConduitResultInterface', @@ -6960,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', @@ -6971,7 +6978,7 @@ phutil_register_library_map(array( 'PhabricatorBadgesTransaction' => 'PhabricatorApplicationTransaction', 'PhabricatorBadgesTransactionComment' => 'PhabricatorApplicationTransactionComment', 'PhabricatorBadgesTransactionQuery' => 'PhabricatorApplicationTransactionQuery', - 'PhabricatorBadgesViewController' => 'PhabricatorBadgesController', + 'PhabricatorBadgesViewController' => 'PhabricatorBadgesProfileController', 'PhabricatorBarePageUIExample' => 'PhabricatorUIExample', 'PhabricatorBarePageView' => 'AphrontPageView', 'PhabricatorBaseURISetupCheck' => 'PhabricatorSetupCheck', @@ -7470,8 +7477,8 @@ phutil_register_library_map(array( 'PhabricatorDashboardAddPanelController' => 'PhabricatorDashboardController', 'PhabricatorDashboardApplication' => 'PhabricatorApplication', 'PhabricatorDashboardArchiveController' => 'PhabricatorDashboardController', + 'PhabricatorDashboardArrangeController' => 'PhabricatorDashboardProfileController', 'PhabricatorDashboardController' => 'PhabricatorController', - 'PhabricatorDashboardCopyController' => 'PhabricatorDashboardController', 'PhabricatorDashboardDAO' => 'PhabricatorLiskDAO', 'PhabricatorDashboardDashboardHasPanelEdgeType' => 'PhabricatorEdgeType', 'PhabricatorDashboardDashboardPHIDType' => 'PhabricatorPHIDType', @@ -7481,7 +7488,7 @@ phutil_register_library_map(array( 'PhabricatorDashboardInstall' => 'PhabricatorDashboardDAO', 'PhabricatorDashboardLayoutConfig' => 'Phobject', 'PhabricatorDashboardListController' => 'PhabricatorDashboardController', - 'PhabricatorDashboardManageController' => 'PhabricatorDashboardController', + 'PhabricatorDashboardManageController' => 'PhabricatorDashboardProfileController', 'PhabricatorDashboardMovePanelController' => 'PhabricatorDashboardController', 'PhabricatorDashboardNgrams' => 'PhabricatorSearchNgrams', 'PhabricatorDashboardPanel' => array( @@ -7520,6 +7527,7 @@ phutil_register_library_map(array( 'PhabricatorDashboardPanelTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorDashboardPanelType' => 'Phobject', 'PhabricatorDashboardPanelViewController' => 'PhabricatorDashboardController', + 'PhabricatorDashboardProfileController' => 'PhabricatorController', 'PhabricatorDashboardProfileMenuItem' => 'PhabricatorProfileMenuItem', 'PhabricatorDashboardQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorDashboardQueryPanelType' => 'PhabricatorDashboardPanelType', @@ -7533,8 +7541,7 @@ phutil_register_library_map(array( 'PhabricatorDashboardTransaction' => 'PhabricatorApplicationTransaction', 'PhabricatorDashboardTransactionEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorDashboardTransactionQuery' => 'PhabricatorApplicationTransactionQuery', - 'PhabricatorDashboardUninstallController' => 'PhabricatorDashboardController', - 'PhabricatorDashboardViewController' => 'PhabricatorDashboardController', + 'PhabricatorDashboardViewController' => 'PhabricatorDashboardProfileController', 'PhabricatorDataCacheSpec' => 'PhabricatorCacheSpec', 'PhabricatorDataNotAttachedException' => 'Exception', 'PhabricatorDatabaseHealthRecord' => 'Phobject', @@ -8007,6 +8014,7 @@ phutil_register_library_map(array( 'PhabricatorMailManagementSendTestWorkflow' => 'PhabricatorMailManagementWorkflow', 'PhabricatorMailManagementShowInboundWorkflow' => 'PhabricatorMailManagementWorkflow', 'PhabricatorMailManagementShowOutboundWorkflow' => 'PhabricatorMailManagementWorkflow', + 'PhabricatorMailManagementUnverifyWorkflow' => 'PhabricatorMailManagementWorkflow', 'PhabricatorMailManagementVolumeWorkflow' => 'PhabricatorMailManagementWorkflow', 'PhabricatorMailManagementWorkflow' => 'PhabricatorManagementWorkflow', 'PhabricatorMailOutboundMailHeraldAdapter' => 'HeraldAdapter', @@ -8099,6 +8107,7 @@ phutil_register_library_map(array( 'PhabricatorModularTransactionType' => 'Phobject', 'PhabricatorMonospacedFontSetting' => 'PhabricatorStringSetting', 'PhabricatorMonospacedTextareasSetting' => 'PhabricatorSelectSetting', + 'PhabricatorMotivatorProfileMenuItem' => 'PhabricatorProfileMenuItem', 'PhabricatorMultiColumnUIExample' => 'PhabricatorUIExample', 'PhabricatorMultiFactorSettingsPanel' => 'PhabricatorSettingsPanel', 'PhabricatorMultimeterApplication' => 'PhabricatorApplication', @@ -8515,6 +8524,7 @@ phutil_register_library_map(array( 'PhabricatorPhurlURLAccessController' => 'PhabricatorPhurlController', 'PhabricatorPhurlURLCommentController' => 'PhabricatorPhurlController', 'PhabricatorPhurlURLCreateCapability' => 'PhabricatorPolicyCapability', + 'PhabricatorPhurlURLDatasource' => 'PhabricatorTypeaheadDatasource', 'PhabricatorPhurlURLEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod', 'PhabricatorPhurlURLEditController' => 'PhabricatorPhurlController', 'PhabricatorPhurlURLEditEngine' => 'PhabricatorEditEngine', @@ -9017,6 +9027,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/auth/controller/PhabricatorAuthUnlinkController.php b/src/applications/auth/controller/PhabricatorAuthUnlinkController.php index 3f694207b9..2c21f63407 100644 --- a/src/applications/auth/controller/PhabricatorAuthUnlinkController.php +++ b/src/applications/auth/controller/PhabricatorAuthUnlinkController.php @@ -61,7 +61,7 @@ final class PhabricatorAuthUnlinkController return id(new AphrontRedirectResponse())->setURI($this->getDoneURI()); } - return $this->renderConfirmDialog($account); + return $this->renderConfirmDialog(); } private function getDoneURI() { 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'; 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/PhabricatorBadgesAwardController.php b/src/applications/badges/controller/PhabricatorBadgesAwardController.php index 0e5679caa4..f9294ec5c6 100644 --- a/src/applications/badges/controller/PhabricatorBadgesAwardController.php +++ b/src/applications/badges/controller/PhabricatorBadgesAwardController.php @@ -40,7 +40,7 @@ final class PhabricatorBadgesAwardController ->setTransactionType(PhabricatorBadgesTransaction::TYPE_AWARD) ->setNewValue($award_phids); - $editor = id(new PhabricatorBadgesEditor($badge)) + $editor = id(new PhabricatorBadgesEditor()) ->setActor($viewer) ->setContentSourceFromRequest($request) ->setContinueOnNoEffect(true) diff --git a/src/applications/badges/controller/PhabricatorBadgesEditRecipientsController.php b/src/applications/badges/controller/PhabricatorBadgesEditRecipientsController.php index a73c6777af..546c41a1d4 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'); @@ -40,7 +40,7 @@ final class PhabricatorBadgesEditRecipientsController ->setTransactionType(PhabricatorBadgesTransaction::TYPE_AWARD) ->setNewValue($award_phids); - $editor = id(new PhabricatorBadgesEditor($badge)) + $editor = id(new PhabricatorBadgesEditor()) ->setActor($viewer) ->setContentSourceFromRequest($request) ->setContinueOnNoEffect(true) @@ -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/PhabricatorBadgesRemoveRecipientsController.php b/src/applications/badges/controller/PhabricatorBadgesRemoveRecipientsController.php index c77a5f33ea..0185698686 100644 --- a/src/applications/badges/controller/PhabricatorBadgesRemoveRecipientsController.php +++ b/src/applications/badges/controller/PhabricatorBadgesRemoveRecipientsController.php @@ -37,7 +37,7 @@ final class PhabricatorBadgesRemoveRecipientsController ->setTransactionType(PhabricatorBadgesTransaction::TYPE_REVOKE) ->setNewValue(array($remove_phid)); - $editor = id(new PhabricatorBadgesEditor($badge)) + $editor = id(new PhabricatorBadgesEditor()) ->setActor($viewer) ->setContentSourceFromRequest($request) ->setContinueOnNoEffect(true) 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); diff --git a/src/applications/base/PhabricatorApplication.php b/src/applications/base/PhabricatorApplication.php index b791aaeef8..93b738d9e0 100644 --- a/src/applications/base/PhabricatorApplication.php +++ b/src/applications/base/PhabricatorApplication.php @@ -251,7 +251,7 @@ abstract class PhabricatorApplication } final protected function getInboundEmailSupportLink() { - return PhabricatorEnv::getDocLink('Configuring Inbound Email'); + return PhabricatorEnv::getDoclink('Configuring Inbound Email'); } public function getAppEmailBlurb() { diff --git a/src/applications/calendar/__tests__/CalendarTimeUtilTestCase.php b/src/applications/calendar/__tests__/CalendarTimeUtilTestCase.php index aa44acec70..646badfe9c 100644 --- a/src/applications/calendar/__tests__/CalendarTimeUtilTestCase.php +++ b/src/applications/calendar/__tests__/CalendarTimeUtilTestCase.php @@ -7,9 +7,7 @@ final class CalendarTimeUtilTestCase extends PhabricatorTestCase { $u->overrideTimezoneIdentifier('America/Los_Angeles'); $days = $this->getAllDays(); foreach ($days as $day) { - $data = CalendarTimeUtil::getCalendarWidgetTimestamps( - $u, - $day); + $data = CalendarTimeUtil::getTimestamps($u, $day, 1); $this->assertEqual( '000000', diff --git a/src/applications/calendar/editor/PhabricatorCalendarExportEditEngine.php b/src/applications/calendar/editor/PhabricatorCalendarExportEditEngine.php index 6ebbc9e1e0..8cd35e7323 100644 --- a/src/applications/calendar/editor/PhabricatorCalendarExportEditEngine.php +++ b/src/applications/calendar/editor/PhabricatorCalendarExportEditEngine.php @@ -70,7 +70,7 @@ final class PhabricatorCalendarExportEditEngine $current_mode = $object->getPolicyMode(); if (empty($export_modes[$current_mode])) { - array_shift($export_modes, $current_mode); + array_unshift($export_modes, $current_mode); } $mode_options = array(); diff --git a/src/applications/calendar/storage/PhabricatorCalendarExternalInvitee.php b/src/applications/calendar/storage/PhabricatorCalendarExternalInvitee.php index 27a23d1e17..80679a9533 100644 --- a/src/applications/calendar/storage/PhabricatorCalendarExternalInvitee.php +++ b/src/applications/calendar/storage/PhabricatorCalendarExternalInvitee.php @@ -14,7 +14,7 @@ final class PhabricatorCalendarExternalInvitee PhabricatorUser $actor, $event) { return id(new PhabricatorCalendarEventInvitee()) ->setInviterPHID($actor->getPHID()) - ->setStatus(self::STATUS_INVITED) + ->setStatus(PhabricatorCalendarEventInvitee::STATUS_INVITED) ->setEventPHID($event->getPHID()); } 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/conduit/controller/PhabricatorConduitController.php b/src/applications/conduit/controller/PhabricatorConduitController.php index 6187421e16..8588bc07f9 100644 --- a/src/applications/conduit/controller/PhabricatorConduitController.php +++ b/src/applications/conduit/controller/PhabricatorConduitController.php @@ -154,7 +154,7 @@ abstract class PhabricatorConduitController extends PhabricatorController { $parts[] = "\n\n"; $parts[] = 'require_once '; - $parts[] = phutil_var_export($libphutil_path, true); + $parts[] = phutil_var_export($libphutil_path); $parts[] = ";\n\n"; $parts[] = '$api_token = "'; @@ -168,7 +168,7 @@ abstract class PhabricatorConduitController extends PhabricatorController { $parts[] = ');'; } else { $params = $this->simplifyParams($params); - $params = phutil_var_export($params, true); + $params = phutil_var_export($params); $parts[] = phutil_tag('strong', array('class' => 'real'), $params); $parts[] = ';'; } @@ -178,7 +178,7 @@ abstract class PhabricatorConduitController extends PhabricatorController { $parts[] = phutil_tag( 'strong', array('class' => 'real'), - phutil_var_export(PhabricatorEnv::getURI('/'), true)); + phutil_var_export(PhabricatorEnv::getURI('/'))); $parts[] = ");\n"; $parts[] = '$client->setConduitToken($api_token);'; @@ -188,7 +188,7 @@ abstract class PhabricatorConduitController extends PhabricatorController { $parts[] = phutil_tag( 'strong', array('class' => 'real'), - phutil_var_export($method->getAPIMethodName(), true)); + phutil_var_export($method->getAPIMethodName())); $parts[] = ', '; $parts[] = '$api_parameters'; $parts[] = ");\n"; 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; } diff --git a/src/applications/config/check/PhabricatorDaemonsSetupCheck.php b/src/applications/config/check/PhabricatorDaemonsSetupCheck.php index 1802e608e9..46ee4efe77 100644 --- a/src/applications/config/check/PhabricatorDaemonsSetupCheck.php +++ b/src/applications/config/check/PhabricatorDaemonsSetupCheck.php @@ -16,7 +16,7 @@ final class PhabricatorDaemonsSetupCheck extends PhabricatorSetupCheck { ->execute(); if (!$task_daemon) { - $doc_href = PhabricatorEnv::getDocLink('Managing Daemons with phd'); + $doc_href = PhabricatorEnv::getDoclink('Managing Daemons with phd'); $summary = pht( 'You must start the Phabricator daemons to send email, rebuild '. diff --git a/src/applications/config/check/PhabricatorPHPConfigSetupCheck.php b/src/applications/config/check/PhabricatorPHPConfigSetupCheck.php index 1dd3add94d..5382a27b7a 100644 --- a/src/applications/config/check/PhabricatorPHPConfigSetupCheck.php +++ b/src/applications/config/check/PhabricatorPHPConfigSetupCheck.php @@ -14,7 +14,7 @@ final class PhabricatorPHPConfigSetupCheck extends PhabricatorSetupCheck { protected function executeChecks() { if (empty($_SERVER['REMOTE_ADDR'])) { - $doc_href = PhabricatorEnv::getDocLink('Configuring a Preamble Script'); + $doc_href = PhabricatorEnv::getDoclink('Configuring a Preamble Script'); $summary = pht( 'You likely need to fix your preamble script so '. diff --git a/src/applications/config/check/PhabricatorSecuritySetupCheck.php b/src/applications/config/check/PhabricatorSecuritySetupCheck.php index d7ae7db53a..518f6c7d54 100644 --- a/src/applications/config/check/PhabricatorSecuritySetupCheck.php +++ b/src/applications/config/check/PhabricatorSecuritySetupCheck.php @@ -52,7 +52,7 @@ final class PhabricatorSecuritySetupCheck extends PhabricatorSetupCheck { $file_key = 'security.alternate-file-domain'; $file_domain = PhabricatorEnv::getEnvConfig($file_key); if (!$file_domain) { - $doc_href = PhabricatorEnv::getDocLink('Configuring a File Domain'); + $doc_href = PhabricatorEnv::getDoclink('Configuring a File Domain'); $this->newIssue('security.'.$file_key) ->setName(pht('Alternate File Domain Not Configured')) diff --git a/src/applications/config/check/PhabricatorStorageSetupCheck.php b/src/applications/config/check/PhabricatorStorageSetupCheck.php index 9ec753da05..09cecfe6d0 100644 --- a/src/applications/config/check/PhabricatorStorageSetupCheck.php +++ b/src/applications/config/check/PhabricatorStorageSetupCheck.php @@ -16,7 +16,7 @@ final class PhabricatorStorageSetupCheck extends PhabricatorSetupCheck { $this->checkS3(); if (!$chunk_engine_active) { - $doc_href = PhabricatorEnv::getDocLink('Configuring File Storage'); + $doc_href = PhabricatorEnv::getDoclink('Configuring File Storage'); $message = pht( 'Large file storage has not been configured, which will limit '. diff --git a/src/applications/config/controller/PhabricatorConfigClusterDatabasesController.php b/src/applications/config/controller/PhabricatorConfigClusterDatabasesController.php index 8753531c7e..03dfa3f64c 100644 --- a/src/applications/config/controller/PhabricatorConfigClusterDatabasesController.php +++ b/src/applications/config/controller/PhabricatorConfigClusterDatabasesController.php @@ -21,7 +21,7 @@ final class PhabricatorConfigClusterDatabasesController ->setText(pht('Documentation'))); $crumbs = $this - ->buildApplicationCrumbs($nav) + ->buildApplicationCrumbs() ->addTextCrumb($title) ->setBorder(true); diff --git a/src/applications/config/controller/PhabricatorConfigClusterNotificationsController.php b/src/applications/config/controller/PhabricatorConfigClusterNotificationsController.php index d0d26d0613..47ab022831 100644 --- a/src/applications/config/controller/PhabricatorConfigClusterNotificationsController.php +++ b/src/applications/config/controller/PhabricatorConfigClusterNotificationsController.php @@ -21,7 +21,7 @@ final class PhabricatorConfigClusterNotificationsController ->setText(pht('Documentation'))); $crumbs = $this - ->buildApplicationCrumbs($nav) + ->buildApplicationCrumbs() ->addTextCrumb($title) ->setBorder(true); diff --git a/src/applications/config/controller/PhabricatorConfigClusterRepositoriesController.php b/src/applications/config/controller/PhabricatorConfigClusterRepositoriesController.php index b3fd9915b1..3531c916a4 100644 --- a/src/applications/config/controller/PhabricatorConfigClusterRepositoriesController.php +++ b/src/applications/config/controller/PhabricatorConfigClusterRepositoriesController.php @@ -22,7 +22,7 @@ final class PhabricatorConfigClusterRepositoriesController ->setText(pht('Documentation'))); $crumbs = $this - ->buildApplicationCrumbs($nav) + ->buildApplicationCrumbs() ->addTextCrumb(pht('Repository Servers')) ->setBorder(true); diff --git a/src/applications/config/controller/PhabricatorConfigIssueListController.php b/src/applications/config/controller/PhabricatorConfigIssueListController.php index 7e4ee758f6..869f53c223 100644 --- a/src/applications/config/controller/PhabricatorConfigIssueListController.php +++ b/src/applications/config/controller/PhabricatorConfigIssueListController.php @@ -49,7 +49,7 @@ final class PhabricatorConfigIssueListController ->setProfileHeader(true); $crumbs = $this - ->buildApplicationCrumbs($nav) + ->buildApplicationCrumbs() ->addTextCrumb(pht('Setup Issues')) ->setBorder(true); 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( 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. diff --git a/src/applications/config/option/PhabricatorSyntaxHighlightingConfigOptions.php b/src/applications/config/option/PhabricatorSyntaxHighlightingConfigOptions.php index 41133d5ede..75d3e8ad6d 100644 --- a/src/applications/config/option/PhabricatorSyntaxHighlightingConfigOptions.php +++ b/src/applications/config/option/PhabricatorSyntaxHighlightingConfigOptions.php @@ -20,7 +20,7 @@ final class PhabricatorSyntaxHighlightingConfigOptions } public function getOptions() { - $caches_href = PhabricatorEnv::getDocLink('Managing Caches'); + $caches_href = PhabricatorEnv::getDoclink('Managing Caches'); return array( $this->newOption( diff --git a/src/applications/config/schema/PhabricatorConfigKeySchema.php b/src/applications/config/schema/PhabricatorConfigKeySchema.php index b30a3641e9..566df54601 100644 --- a/src/applications/config/schema/PhabricatorConfigKeySchema.php +++ b/src/applications/config/schema/PhabricatorConfigKeySchema.php @@ -9,6 +9,7 @@ final class PhabricatorConfigKeySchema private $unique; private $table; private $indexType; + private $property; public function setIndexType($index_type) { $this->indexType = $index_type; diff --git a/src/applications/conpherence/conduit/ConpherenceCreateThreadConduitAPIMethod.php b/src/applications/conpherence/conduit/ConpherenceCreateThreadConduitAPIMethod.php index 85f450a648..9cae87e10a 100644 --- a/src/applications/conpherence/conduit/ConpherenceCreateThreadConduitAPIMethod.php +++ b/src/applications/conpherence/conduit/ConpherenceCreateThreadConduitAPIMethod.php @@ -50,9 +50,6 @@ final class ConpherenceCreateThreadConduitAPIMethod if ($errors) { foreach ($errors as $error_code) { switch ($error_code) { - case ConpherenceEditor::ERROR_EMPTY_TITLE: - throw new ConduitException('ERR_EMPTY_TITLE'); - break; case ConpherenceEditor::ERROR_EMPTY_PARTICIPANTS: throw new ConduitException('ERR_EMPTY_PARTICIPANT_PHIDS'); break; diff --git a/src/applications/dashboard/application/PhabricatorDashboardApplication.php b/src/applications/dashboard/application/PhabricatorDashboardApplication.php index 54ec5db20a..123dcc9f6e 100644 --- a/src/applications/dashboard/application/PhabricatorDashboardApplication.php +++ b/src/applications/dashboard/application/PhabricatorDashboardApplication.php @@ -27,10 +27,9 @@ 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', - 'uninstall/(?P\d+)/' => 'PhabricatorDashboardUninstallController', 'addpanel/(?P\d+)/' => 'PhabricatorDashboardAddPanelController', 'movepanel/(?P\d+)/' => 'PhabricatorDashboardMovePanelController', 'removepanel/(?P\d+)/' diff --git a/src/applications/dashboard/controller/PhabricatorDashboardAddPanelController.php b/src/applications/dashboard/controller/PhabricatorDashboardAddPanelController.php index 3e733edb3e..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, @@ -20,9 +21,10 @@ 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'); + $v_panel = head($request->getArr('panel')); $e_panel = true; $errors = array(); if ($request->isFormPost()) { @@ -32,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'); @@ -69,26 +80,18 @@ 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)); + ->setLabel(pht('Panel'))); return $this->newDialog() ->setTitle(pht('Add Panel')) diff --git a/src/applications/dashboard/controller/PhabricatorDashboardArrangeController.php b/src/applications/dashboard/controller/PhabricatorDashboardArrangeController.php new file mode 100644 index 0000000000..ed8d24d737 --- /dev/null +++ b/src/applications/dashboard/controller/PhabricatorDashboardArrangeController.php @@ -0,0 +1,71 @@ +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.'); + + $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 deleted file mode 100644 index 6b89915c76..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(); - } - - $manage_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); - - $manage_uri = $this->getApplicationURI('edit/'.$copy->getID().'/'); - return id(new AphrontRedirectResponse())->setURI($manage_uri); - } - - return $this->newDialog() - ->setTitle(pht('Copy Dashboard')) - ->appendParagraph( - pht( - 'Create a copy of the dashboard "%s"?', - phutil_tag('strong', array(), $dashboard->getName()))) - ->addCancelButton($manage_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..39a7e46841 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,41 +33,27 @@ 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); - $curtain = $this->buildCurtainview($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) { $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) ->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 +61,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(); @@ -149,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 787d1c63ee..cc7502afef 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) { @@ -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; @@ -162,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), @@ -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('manage/'.$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/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/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/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/customfield/PhabricatorDashboardPanelTabsCustomField.php b/src/applications/dashboard/customfield/PhabricatorDashboardPanelTabsCustomField.php index f473b3f6cd..96566db54a 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) { @@ -29,26 +33,54 @@ 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 // 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 +89,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)); } diff --git a/src/applications/dashboard/engine/PhabricatorDashboardPanelRenderingEngine.php b/src/applications/dashboard/engine/PhabricatorDashboardPanelRenderingEngine.php index fbd5aaa2bb..dfe328933a 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; } @@ -78,7 +88,6 @@ final class PhabricatorDashboardPanelRenderingEngine extends Phobject { public function renderPanel() { $panel = $this->getPanel(); - $viewer = $this->getViewer(); if (!$panel) { return $this->renderErrorPanel( @@ -107,7 +116,7 @@ final class PhabricatorDashboardPanelRenderingEngine extends Phobject { } } - return $this->renderNormalPanel($viewer, $panel, $this); + return $this->renderNormalPanel(); } catch (Exception $ex) { return $this->renderErrorPanel( $panel->getName(), @@ -221,8 +230,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/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/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..b4772ba83f 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.'); } @@ -93,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/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/query/PhabricatorDashboardSearchEngine.php b/src/applications/dashboard/query/PhabricatorDashboardSearchEngine.php index c6c6ab1233..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,100 +98,53 @@ final class PhabricatorDashboardSearchEngine PhabricatorSavedQuery $query, array $handles) { - $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(); + $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 = 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) { + foreach ($dashboards as $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()); - - $item->addAttribute( - id(new PHUIHandleTagListView()) - ->setLimit(4) - ->setNoDataString(pht('No Projects')) - ->setSlim(true) - ->setHandles($project_handles)); - if ($dashboard->isArchived()) { $item->setDisabled(true); } - $can_edit = PhabricatorPolicyFilter::hasCapability( - $viewer, - $dashboard, - PhabricatorPolicyCapability::CAN_EDIT); + $panels = $dashboard->getPanels(); + foreach ($panels as $panel) { + $item->addAttribute($panel->getName()); + } - $href_view = $this->getApplicationURI("manage/{$id}/"); - $item->addAction( - id(new PHUIListItemView()) - ->setName(pht('Manage')) - ->setIcon('fa-th') - ->setHref($href_view)); + if (empty($panels)) { + $empty = phutil_tag('em', array(), pht('No panels.')); + $item->addAttribute($empty); + } - $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()); + + $author_phid = $dashboard->getAuthorPHID(); + $author_name = $handles[$author_phid]->renderLink(); + $item->addByline(pht('Author: %s', $author_name)); $list->addItem($item); } 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, 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/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; } } diff --git a/src/applications/differential/customfield/DifferentialCustomField.php b/src/applications/differential/customfield/DifferentialCustomField.php index 487e412f66..0382034a0e 100644 --- a/src/applications/differential/customfield/DifferentialCustomField.php +++ b/src/applications/differential/customfield/DifferentialCustomField.php @@ -111,8 +111,8 @@ abstract class DifferentialCustomField * @task diff */ public function renderDiffPropertyViewLabel(DifferentialDiff $diff) { - if ($this->proxy) { - return $this->proxy->renderDiffPropertyViewLabel($diff); + if ($this->getProxy()) { + return $this->getProxy()->renderDiffPropertyViewLabel($diff); } return $this->getFieldName(); } @@ -122,8 +122,8 @@ abstract class DifferentialCustomField * @task diff */ public function renderDiffPropertyViewValue(DifferentialDiff $diff) { - if ($this->proxy) { - return $this->proxy->renderDiffPropertyViewValue($diff); + if ($this->getProxy()) { + return $this->getProxy()->renderDiffPropertyViewValue($diff); } throw new PhabricatorCustomFieldImplementationIncompleteException($this); } diff --git a/src/applications/differential/query/DifferentialRevisionRequiredActionResultBucket.php b/src/applications/differential/query/DifferentialRevisionRequiredActionResultBucket.php index b9fec508c5..64570bf2cc 100644 --- a/src/applications/differential/query/DifferentialRevisionRequiredActionResultBucket.php +++ b/src/applications/differential/query/DifferentialRevisionRequiredActionResultBucket.php @@ -20,7 +20,7 @@ final class DifferentialRevisionRequiredActionResultBucket $this->objects = $objects; - $phids = $query->getEvaluatedParameter('responsiblePHIDs', array()); + $phids = $query->getEvaluatedParameter('responsiblePHIDs'); if (!$phids) { throw new Exception( pht( diff --git a/src/applications/diffusion/conduit/DiffusionDiffQueryConduitAPIMethod.php b/src/applications/diffusion/conduit/DiffusionDiffQueryConduitAPIMethod.php index d8ce38b5d5..694d4bc012 100644 --- a/src/applications/diffusion/conduit/DiffusionDiffQueryConduitAPIMethod.php +++ b/src/applications/diffusion/conduit/DiffusionDiffQueryConduitAPIMethod.php @@ -201,7 +201,7 @@ final class DiffusionDiffQueryConduitAPIMethod $effective_commit = $this->getEffectiveCommit($request); if (!$effective_commit) { - return $this->getEmptyResult(1); + return $this->getEmptyResult(); } $raw_query = DiffusionRawDiffQuery::newFromDiffusionRequest($drequest) @@ -209,7 +209,7 @@ final class DiffusionDiffQueryConduitAPIMethod $raw_diff = $raw_query->executeInline(); if (!$raw_diff) { - return $this->getEmptyResult(2); + return $this->getEmptyResult(); } $parser = $this->getDefaultParser(); diff --git a/src/applications/diffusion/controller/DiffusionBrowseController.php b/src/applications/diffusion/controller/DiffusionBrowseController.php index f9d7b6792f..aa8e370e25 100644 --- a/src/applications/diffusion/controller/DiffusionBrowseController.php +++ b/src/applications/diffusion/controller/DiffusionBrowseController.php @@ -44,7 +44,7 @@ final class DiffusionBrowseController extends DiffusionController { $is_file = ($reason == DiffusionBrowseResultSet::REASON_IS_FILE); if ($is_file) { - return $this->browseFile($results); + return $this->browseFile(); } else { $paths = $results->getPaths(); $paths = $pager->sliceResults($paths); 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; } diff --git a/src/applications/diffusion/controller/DiffusionController.php b/src/applications/diffusion/controller/DiffusionController.php index 61c17e0877..eb46211d99 100644 --- a/src/applications/diffusion/controller/DiffusionController.php +++ b/src/applications/diffusion/controller/DiffusionController.php @@ -357,7 +357,7 @@ abstract class DiffusionController extends PhabricatorController { $stable_commit = $drequest->getStableCommit(); $stable_commit_hash = PhabricatorHash::digestForIndex($stable_commit); - $readme_path_hash = PhabricatorHash::digestForindex($readme_path); + $readme_path_hash = PhabricatorHash::digestForIndex($readme_path); $cache = PhabricatorCaches::getMutableStructureCache(); $cache_key = "diffusion". diff --git a/src/applications/diffusion/controller/DiffusionHistoryController.php b/src/applications/diffusion/controller/DiffusionHistoryController.php index eca8fe2a2f..c9df551c43 100644 --- a/src/applications/diffusion/controller/DiffusionHistoryController.php +++ b/src/applications/diffusion/controller/DiffusionHistoryController.php @@ -59,7 +59,7 @@ final class DiffusionHistoryController extends DiffusionController { ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) ->setTable($history_table); - $header = $this->buildHeader($drequest, $repository); + $header = $this->buildHeader($drequest); $crumbs = $this->buildCrumbs( array( diff --git a/src/applications/diffusion/management/DiffusionRepositoryStatusManagementPanel.php b/src/applications/diffusion/management/DiffusionRepositoryStatusManagementPanel.php index 0fb220c385..324338443d 100644 --- a/src/applications/diffusion/management/DiffusionRepositoryStatusManagementPanel.php +++ b/src/applications/diffusion/management/DiffusionRepositoryStatusManagementPanel.php @@ -241,7 +241,7 @@ final class DiffusionRepositoryStatusManagementPanel } } - $doc_href = PhabricatorEnv::getDocLink('Managing Daemons with phd'); + $doc_href = PhabricatorEnv::getDoclink('Managing Daemons with phd'); $daemon_instructions = pht( 'Use %s to start daemons. See %s.', 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( diff --git a/src/applications/diffusion/query/DiffusionCommitRequiredActionResultBucket.php b/src/applications/diffusion/query/DiffusionCommitRequiredActionResultBucket.php index 41840bcb72..40bc63025d 100644 --- a/src/applications/diffusion/query/DiffusionCommitRequiredActionResultBucket.php +++ b/src/applications/diffusion/query/DiffusionCommitRequiredActionResultBucket.php @@ -17,7 +17,7 @@ final class DiffusionCommitRequiredActionResultBucket $this->objects = $objects; - $phids = $query->getEvaluatedParameter('responsiblePHIDs', array()); + $phids = $query->getEvaluatedParameter('responsiblePHIDs'); if (!$phids) { throw new Exception( pht( diff --git a/src/applications/diviner/atom/DivinerAtom.php b/src/applications/diviner/atom/DivinerAtom.php index 520a51e26b..f7f8d2c4ac 100644 --- a/src/applications/diviner/atom/DivinerAtom.php +++ b/src/applications/diviner/atom/DivinerAtom.php @@ -43,7 +43,7 @@ final class DivinerAtom extends Phobject { $this->getContext(), $this->getName(), $this->getFile(), - sprintf('%08', $this->getLine()), + sprintf('%08d', $this->getLine()), )); } diff --git a/src/applications/diviner/renderer/DivinerDefaultRenderer.php b/src/applications/diviner/renderer/DivinerDefaultRenderer.php index 6ec70f2a3c..a4c551e93d 100644 --- a/src/applications/diviner/renderer/DivinerDefaultRenderer.php +++ b/src/applications/diviner/renderer/DivinerDefaultRenderer.php @@ -94,7 +94,7 @@ final class DivinerDefaultRenderer extends DivinerRenderer { $this->pushAtomStack($atom); $description = $engine->markupText($text); - $this->popAtomStack($atom); + $this->popAtomStack(); return phutil_tag( 'div', 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()); diff --git a/src/applications/diviner/workflow/DivinerWorkflow.php b/src/applications/diviner/workflow/DivinerWorkflow.php index 152910a477..69fcc67f48 100644 --- a/src/applications/diviner/workflow/DivinerWorkflow.php +++ b/src/applications/diviner/workflow/DivinerWorkflow.php @@ -61,7 +61,7 @@ abstract class DivinerWorkflow extends PhabricatorManagementWorkflow { } foreach (idx($book, 'groups', array()) as $group) { - PhutilTypeSpec::checkmap( + PhutilTypeSpec::checkMap( $group, array( 'name' => 'string', 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'); diff --git a/src/applications/herald/controller/HeraldController.php b/src/applications/herald/controller/HeraldController.php index 355d3b90f9..1a5d2084dd 100644 --- a/src/applications/herald/controller/HeraldController.php +++ b/src/applications/herald/controller/HeraldController.php @@ -3,7 +3,7 @@ abstract class HeraldController extends PhabricatorController { public function buildApplicationMenu() { - return $this->buildSideNavView(true)->getMenu(); + return $this->buildSideNavView()->getMenu(); } protected function buildApplicationCrumbs() { diff --git a/src/applications/herald/query/HeraldRuleQuery.php b/src/applications/herald/query/HeraldRuleQuery.php index e2c5f6928b..88df18db24 100644 --- a/src/applications/herald/query/HeraldRuleQuery.php +++ b/src/applications/herald/query/HeraldRuleQuery.php @@ -40,11 +40,6 @@ final class HeraldRuleQuery extends PhabricatorCursorPagedPolicyAwareQuery { return $this; } - public function withExecutableRules($executable) { - $this->executable = $executable; - return $this; - } - public function withDisabled($disabled) { $this->disabled = $disabled; return $this; diff --git a/src/applications/legalpad/controller/LegalpadDocumentEditController.php b/src/applications/legalpad/controller/LegalpadDocumentEditController.php index 3804885edb..8f84f60339 100644 --- a/src/applications/legalpad/controller/LegalpadDocumentEditController.php +++ b/src/applications/legalpad/controller/LegalpadDocumentEditController.php @@ -213,7 +213,7 @@ final class LegalpadDocumentEditController extends LegalpadController { ->setPolicies($policies) ->setName('can_edit')); - $crumbs = $this->buildApplicationCrumbs($this->buildSideNav()); + $crumbs = $this->buildApplicationCrumbs(); $submit = new AphrontFormSubmitControl(); if ($is_create) { $submit->setValue(pht('Create Document')); diff --git a/src/applications/legalpad/controller/LegalpadDocumentManageController.php b/src/applications/legalpad/controller/LegalpadDocumentManageController.php index 1a39f2c143..6d9360a731 100644 --- a/src/applications/legalpad/controller/LegalpadDocumentManageController.php +++ b/src/applications/legalpad/controller/LegalpadDocumentManageController.php @@ -54,7 +54,7 @@ final class LegalpadDocumentManageController extends LegalpadController { $add_comment = $this->buildAddCommentView($document, $comment_form_id); - $crumbs = $this->buildApplicationCrumbs($this->buildSideNav()); + $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb( $document->getMonogram(), '/'.$document->getMonogram()); diff --git a/src/applications/legalpad/storage/LegalpadDocumentBody.php b/src/applications/legalpad/storage/LegalpadDocumentBody.php index a55583428c..a3fdf20f5f 100644 --- a/src/applications/legalpad/storage/LegalpadDocumentBody.php +++ b/src/applications/legalpad/storage/LegalpadDocumentBody.php @@ -52,9 +52,6 @@ final class LegalpadDocumentBody extends LegalpadDAO case self::MARKUP_FIELD_TEXT: $text = $this->getText(); break; - case self::MARKUP_FIELD_TITLE: - $text = $this->getTitle(); - break; default: throw new Exception(pht('Unknown field: %s', $field)); break; diff --git a/src/applications/lipsum/generator/PhabricatorTestDataGenerator.php b/src/applications/lipsum/generator/PhabricatorTestDataGenerator.php index b44895ae87..2617c755df 100644 --- a/src/applications/lipsum/generator/PhabricatorTestDataGenerator.php +++ b/src/applications/lipsum/generator/PhabricatorTestDataGenerator.php @@ -98,8 +98,10 @@ abstract class PhabricatorTestDataGenerator extends Phobject { ->loadOneWhere('1 = 1 ORDER BY RAND() LIMIT 1'); } catch (PhutilMissingSymbolException $ex) { throw new PhutilMissingSymbolException( + $classname, + pht('class'), pht( - 'Unable to load symbol %s: this class does not exit.', + 'Unable to load symbol %s: this class does not exist.', $classname)); } } diff --git a/src/applications/maniphest/controller/ManiphestController.php b/src/applications/maniphest/controller/ManiphestController.php index 17ba6cb548..c80a1a462a 100644 --- a/src/applications/maniphest/controller/ManiphestController.php +++ b/src/applications/maniphest/controller/ManiphestController.php @@ -3,7 +3,7 @@ abstract class ManiphestController extends PhabricatorController { public function buildApplicationMenu() { - return $this->buildSideNavView(true)->getMenu(); + return $this->buildSideNavView()->getMenu(); } public function buildSideNavView() { diff --git a/src/applications/maniphest/controller/ManiphestTaskDetailController.php b/src/applications/maniphest/controller/ManiphestTaskDetailController.php index ca0fe5466e..369986705c 100644 --- a/src/applications/maniphest/controller/ManiphestTaskDetailController.php +++ b/src/applications/maniphest/controller/ManiphestTaskDetailController.php @@ -219,7 +219,7 @@ final class ManiphestTaskDetailController extends ManiphestController { $status = $task->getStatus(); $status_name = ManiphestTaskStatus::renderFullDescription( - $status, $priority_name, $priority_color); + $status, $priority_name); $view->addProperty(PHUIHeaderView::PROPERTY_STATUS, $status_name); $view->setHeaderIcon(ManiphestTaskStatus::getStatusIcon( diff --git a/src/applications/maniphest/field/ManiphestConfiguredCustomField.php b/src/applications/maniphest/field/ManiphestConfiguredCustomField.php index 9e6b4f038b..68c20c70bc 100644 --- a/src/applications/maniphest/field/ManiphestConfiguredCustomField.php +++ b/src/applications/maniphest/field/ManiphestConfiguredCustomField.php @@ -10,8 +10,7 @@ final class ManiphestConfiguredCustomField public function createFields($object) { $config = PhabricatorEnv::getEnvConfig( - 'maniphest.custom-field-definitions', - array()); + 'maniphest.custom-field-definitions'); $fields = PhabricatorStandardCustomField::buildStandardFields( $this, $config); diff --git a/src/applications/maniphest/storage/ManiphestTransaction.php b/src/applications/maniphest/storage/ManiphestTransaction.php index 89e416b174..835230067f 100644 --- a/src/applications/maniphest/storage/ManiphestTransaction.php +++ b/src/applications/maniphest/storage/ManiphestTransaction.php @@ -767,7 +767,7 @@ final class ManiphestTransaction $new_name); } else { return pht( - '%s changed the status of %s, a subtasktask of %s, '. + '%s changed the status of %s, a subtask of %s, '. 'from "%s" to "%s".', $this->renderHandleLink($author_phid), $this->renderHandleLink($blocker_phid), diff --git a/src/applications/metamta/adapter/PhabricatorMailImplementationPHPMailerAdapter.php b/src/applications/metamta/adapter/PhabricatorMailImplementationPHPMailerAdapter.php index 8f7e809d6c..2fadd6491f 100644 --- a/src/applications/metamta/adapter/PhabricatorMailImplementationPHPMailerAdapter.php +++ b/src/applications/metamta/adapter/PhabricatorMailImplementationPHPMailerAdapter.php @@ -15,7 +15,7 @@ final class PhabricatorMailImplementationPHPMailerAdapter $this->mailer = new PHPMailer($use_exceptions = true); $this->mailer->CharSet = 'utf-8'; - $encoding = PhabricatorEnv::getEnvConfig('phpmailer.smtp-encoding', '8bit'); + $encoding = PhabricatorEnv::getEnvConfig('phpmailer.smtp-encoding'); $this->mailer->Encoding = $encoding; // By default, PHPMailer sends one mail per recipient. We handle diff --git a/src/applications/metamta/adapter/PhabricatorMailImplementationPHPMailerLiteAdapter.php b/src/applications/metamta/adapter/PhabricatorMailImplementationPHPMailerLiteAdapter.php index 2a8b12b64a..f072e769c3 100644 --- a/src/applications/metamta/adapter/PhabricatorMailImplementationPHPMailerLiteAdapter.php +++ b/src/applications/metamta/adapter/PhabricatorMailImplementationPHPMailerLiteAdapter.php @@ -18,7 +18,7 @@ class PhabricatorMailImplementationPHPMailerLiteAdapter $this->mailer = new PHPMailerLite($use_exceptions = true); $this->mailer->CharSet = 'utf-8'; - $encoding = PhabricatorEnv::getEnvConfig('phpmailer.smtp-encoding', '8bit'); + $encoding = PhabricatorEnv::getEnvConfig('phpmailer.smtp-encoding'); $this->mailer->Encoding = $encoding; // By default, PHPMailerLite sends one mail per recipient. We handle 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/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/PhabricatorMetaMTAAttachment.php b/src/applications/metamta/storage/PhabricatorMetaMTAAttachment.php index 96d2f50f0a..b26bb0b8a7 100644 --- a/src/applications/metamta/storage/PhabricatorMetaMTAAttachment.php +++ b/src/applications/metamta/storage/PhabricatorMetaMTAAttachment.php @@ -41,7 +41,7 @@ final class PhabricatorMetaMTAAttachment extends Phobject { public function toDictionary() { return array( 'filename' => $this->getFilename(), - 'mimetype' => $this->getMimetype(), + 'mimetype' => $this->getMimeType(), 'data' => $this->getData(), ); } 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() { diff --git a/src/applications/owners/customfield/PhabricatorOwnersConfiguredCustomField.php b/src/applications/owners/customfield/PhabricatorOwnersConfiguredCustomField.php index a35296311f..092ebf41cc 100644 --- a/src/applications/owners/customfield/PhabricatorOwnersConfiguredCustomField.php +++ b/src/applications/owners/customfield/PhabricatorOwnersConfiguredCustomField.php @@ -9,9 +9,7 @@ final class PhabricatorOwnersConfiguredCustomField } public function createFields($object) { - $config = PhabricatorEnv::getEnvConfig( - 'owners.custom-field-definitions', - array()); + $config = PhabricatorEnv::getEnvConfig('owners.custom-field-definitions'); $fields = PhabricatorStandardCustomField::buildStandardFields( $this, diff --git a/src/applications/paste/query/PhabricatorPasteQuery.php b/src/applications/paste/query/PhabricatorPasteQuery.php index 110083a64e..7ecd83447a 100644 --- a/src/applications/paste/query/PhabricatorPasteQuery.php +++ b/src/applications/paste/query/PhabricatorPasteQuery.php @@ -292,7 +292,7 @@ final class PhabricatorPasteQuery foreach ($pastes as $paste) { $key = $this->getSnippetCacheKey($paste); if (isset($caches[$key])) { - $snippet_data = phutil_json_decode($caches[$key], true); + $snippet_data = phutil_json_decode($caches[$key]); $snippet = new PhabricatorPasteSnippet( phutil_safe_html($snippet_data['content']), $snippet_data['type'], diff --git a/src/applications/paste/xaction/PhabricatorPasteTitleTransaction.php b/src/applications/paste/xaction/PhabricatorPasteTitleTransaction.php index 931a78df96..56fc913558 100644 --- a/src/applications/paste/xaction/PhabricatorPasteTitleTransaction.php +++ b/src/applications/paste/xaction/PhabricatorPasteTitleTransaction.php @@ -15,7 +15,7 @@ final class PhabricatorPasteTitleTransaction public function getTitle() { $old = $this->getOldValue(); - $new = $this->getNeWValue(); + $new = $this->getNewValue(); if (strlen($old) && strlen($new)) { return pht( @@ -38,7 +38,7 @@ final class PhabricatorPasteTitleTransaction public function getTitleForFeed() { $old = $this->getOldValue(); - $new = $this->getNeWValue(); + $new = $this->getNewValue(); if (strlen($old) && strlen($new)) { return pht( diff --git a/src/applications/people/controller/PhabricatorPeopleProfileController.php b/src/applications/people/controller/PhabricatorPeopleProfileController.php index bd44169ef7..7393df8455 100644 --- a/src/applications/people/controller/PhabricatorPeopleProfileController.php +++ b/src/applications/people/controller/PhabricatorPeopleProfileController.php @@ -103,6 +103,8 @@ abstract class PhabricatorPeopleProfileController if ($user->getIsDisabled()) { $header->setStatus('fa-ban', 'red', pht('Disabled')); + } else if (!$user->getIsEmailVerified()) { + $header->setStatus('fa-envelope', 'red', pht('Email Not Verified')); } else { $header->setStatus($profile_icon, 'bluegrey', $profile_title); } 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/people/customfield/PhabricatorUserConfiguredCustomField.php b/src/applications/people/customfield/PhabricatorUserConfiguredCustomField.php index 9c58b970bb..800ea320c3 100644 --- a/src/applications/people/customfield/PhabricatorUserConfiguredCustomField.php +++ b/src/applications/people/customfield/PhabricatorUserConfiguredCustomField.php @@ -11,7 +11,7 @@ final class PhabricatorUserConfiguredCustomField public function createFields($object) { return PhabricatorStandardCustomField::buildStandardFields( $this, - PhabricatorEnv::getEnvConfig('user.custom-field-definitions', array())); + PhabricatorEnv::getEnvConfig('user.custom-field-definitions')); } public function newStorageObject() { diff --git a/src/applications/people/markup/PhabricatorMentionRemarkupRule.php b/src/applications/people/markup/PhabricatorMentionRemarkupRule.php index 92697f018c..778384e946 100644 --- a/src/applications/people/markup/PhabricatorMentionRemarkupRule.php +++ b/src/applications/people/markup/PhabricatorMentionRemarkupRule.php @@ -150,7 +150,7 @@ final class PhabricatorMentionRemarkupRule extends PhutilRemarkupRule { $tag->addClass('phabricator-remarkup-mention-nopermission'); } - if (!$user->isUserActivated()) { + if (!$user->isResponsive()) { $tag->setDotColor(PHUITagView::COLOR_GREY); } else { if ($user->getAwayUntil()) { diff --git a/src/applications/people/phid/PhabricatorPeopleUserPHIDType.php b/src/applications/people/phid/PhabricatorPeopleUserPHIDType.php index 77e0088c5e..2d773121a0 100644 --- a/src/applications/people/phid/PhabricatorPeopleUserPHIDType.php +++ b/src/applications/people/phid/PhabricatorPeopleUserPHIDType.php @@ -61,7 +61,7 @@ final class PhabricatorPeopleUserPHIDType extends PhabricatorPHIDType { } $availability = null; - if (!$user->isUserActivated()) { + if (!$user->isResponsive()) { $availability = PhabricatorObjectHandle::AVAILABILITY_DISABLED; } else { $until = $user->getAwayUntil(); diff --git a/src/applications/people/storage/PhabricatorUser.php b/src/applications/people/storage/PhabricatorUser.php index 61b2209c24..813d11c868 100644 --- a/src/applications/people/storage/PhabricatorUser.php +++ b/src/applications/people/storage/PhabricatorUser.php @@ -120,6 +120,32 @@ final class PhabricatorUser return true; } + + /** + * Is this a user who we can reasonably expect to respond to requests? + * + * This is used to provide a grey "disabled/unresponsive" dot cue when + * rendering handles and tags, so it isn't a surprise if you get ignored + * when you ask things of users who will not receive notifications or could + * not respond to them (because they are disabled, unapproved, do not have + * verified email addresses, etc). + * + * @return bool True if this user can receive and respond to requests from + * other humans. + */ + public function isResponsive() { + if (!$this->isUserActivated()) { + return false; + } + + if (!$this->getIsEmailVerified()) { + return false; + } + + return true; + } + + public function canEstablishWebSessions() { if ($this->getIsMailingList()) { return false; diff --git a/src/applications/people/view/PhabricatorUserCardView.php b/src/applications/people/view/PhabricatorUserCardView.php index 0b9bc439ab..bb0ab9eebc 100644 --- a/src/applications/people/view/PhabricatorUserCardView.php +++ b/src/applications/people/view/PhabricatorUserCardView.php @@ -52,17 +52,44 @@ final class PhabricatorUserCardView extends AphrontTagView { require_celerity_resource('project-card-view-css'); - $profile_icon = PhabricatorPeopleIconSet::getIconIcon($profile->getIcon()); - $profile_title = $profile->getDisplayTitle(); + // We don't have a ton of room on the hovercard, so we're trying to show + // the most important tag. Users can click through to the profile to get + // more details. + + if ($user->getIsDisabled()) { + $tag_icon = 'fa-ban'; + $tag_title = pht('Disabled'); + $tag_shade = PHUITagView::COLOR_RED; + } else if (!$user->getIsApproved()) { + $tag_icon = 'fa-ban'; + $tag_title = pht('Unapproved Account'); + $tag_shade = PHUITagView::COLOR_RED; + } else if (!$user->getIsEmailVerified()) { + $tag_icon = 'fa-envelope'; + $tag_title = pht('Email Not Verified'); + $tag_shade = PHUITagView::COLOR_RED; + } else if ($user->getIsAdmin()) { + $tag_icon = 'fa-star'; + $tag_title = pht('Administrator'); + $tag_shade = PHUITagView::COLOR_INDIGO; + } else { + $tag_icon = PhabricatorPeopleIconSet::getIconIcon($profile->getIcon()); + $tag_title = $profile->getDisplayTitle(); + $tag_shade = null; + } $tag = id(new PHUITagView()) - ->setIcon($profile_icon) - ->setName($profile_title) - ->addClass('project-view-header-tag') + ->setIcon($tag_icon) + ->setName($tag_title) ->setType(PHUITagView::TYPE_SHADE); + if ($tag_shade !== null) { + $tag->setShade($tag_shade); + } + $header = id(new PHUIHeaderView()) - ->setHeader(array($user->getFullName(), $tag)) + ->setHeader($user->getFullName()) + ->addTag($tag) ->setUser($viewer) ->setImage($picture); @@ -70,7 +97,7 @@ final class PhabricatorUserCardView extends AphrontTagView { $body[] = $this->addItem( pht('User Since'), - phabricator_date($profile->getDateCreated(), $viewer)); + phabricator_date($user->getDateCreated(), $viewer)); if (PhabricatorApplication::isClassInstalledForViewer( 'PhabricatorCalendarApplication', 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(); diff --git a/src/applications/phame/storage/PhamePost.php b/src/applications/phame/storage/PhamePost.php index fb959e61f7..6e9e005bfa 100644 --- a/src/applications/phame/storage/PhamePost.php +++ b/src/applications/phame/storage/PhamePost.php @@ -172,7 +172,7 @@ final class PhamePost extends PhameDAO } public function getSlug() { - return PhabricatorSlug::normalizeProjectSlug($this->getTitle(), true); + return PhabricatorSlug::normalizeProjectSlug($this->getTitle()); } public function getHeaderImageURI() { diff --git a/src/applications/phid/utils.php b/src/applications/phid/utils.php index d667473190..152a547284 100644 --- a/src/applications/phid/utils.php +++ b/src/applications/phid/utils.php @@ -5,7 +5,7 @@ * PhabricatorPHIDConstants::PHID_TYPE_UNKNOWN if it fails to look up the type * * @param phid Anything. - * @return A value from PhabricatorPHIDConstants (ideally) + * @return string A value from PhabricatorPHIDConstants (ideally) */ function phid_get_type($phid) { $matches = null; diff --git a/src/applications/pholio/controller/PholioMockViewController.php b/src/applications/pholio/controller/PholioMockViewController.php index a1fb40c86b..2ab31d0d96 100644 --- a/src/applications/pholio/controller/PholioMockViewController.php +++ b/src/applications/pholio/controller/PholioMockViewController.php @@ -67,7 +67,7 @@ final class PholioMockViewController extends PholioController { $timeline->setMock($mock); $curtain = $this->buildCurtainView($mock); - $details = $this->buildDescriptionView($mock, $engine); + $details = $this->buildDescriptionView($mock); require_celerity_resource('pholio-css'); require_celerity_resource('pholio-inline-comments-css'); 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', diff --git a/src/applications/phragment/storage/PhragmentFragment.php b/src/applications/phragment/storage/PhragmentFragment.php index af733ab730..0f04783419 100644 --- a/src/applications/phragment/storage/PhragmentFragment.php +++ b/src/applications/phragment/storage/PhragmentFragment.php @@ -10,6 +10,7 @@ final class PhragmentFragment extends PhragmentDAO protected $editPolicy; private $latestVersion = self::ATTACHABLE; + private $file = self::ATTACHABLE; protected function getConfiguration() { return array( diff --git a/src/applications/phriction/conduit/PhrictionInfoConduitAPIMethod.php b/src/applications/phriction/conduit/PhrictionInfoConduitAPIMethod.php index 60d9ece734..360b3e7b93 100644 --- a/src/applications/phriction/conduit/PhrictionInfoConduitAPIMethod.php +++ b/src/applications/phriction/conduit/PhrictionInfoConduitAPIMethod.php @@ -38,9 +38,7 @@ final class PhrictionInfoConduitAPIMethod extends PhrictionConduitAPIMethod { throw new ConduitException('ERR-BAD-DOCUMENT'); } - return $this->buildDocumentInfoDictionary( - $document, - $document->getContent()); + return $this->buildDocumentInfoDictionary($document); } } 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); + } + +} diff --git a/src/applications/policy/controller/PhabricatorPolicyExplainController.php b/src/applications/policy/controller/PhabricatorPolicyExplainController.php index 45ac0ee5e1..da4103765b 100644 --- a/src/applications/policy/controller/PhabricatorPolicyExplainController.php +++ b/src/applications/policy/controller/PhabricatorPolicyExplainController.php @@ -85,7 +85,7 @@ final class PhabricatorPolicyExplainController return null; } - if (!PhabricatorSpacesNamespaceQuery::getSpacesExist($viewer)) { + if (!PhabricatorSpacesNamespaceQuery::getSpacesExist()) { return null; } diff --git a/src/applications/ponder/controller/PonderQuestionViewController.php b/src/applications/ponder/controller/PonderQuestionViewController.php index 529c396328..59da519834 100644 --- a/src/applications/ponder/controller/PonderQuestionViewController.php +++ b/src/applications/ponder/controller/PonderQuestionViewController.php @@ -83,7 +83,7 @@ final class PonderQuestionViewController extends PonderController { ->setContentID($content_id) ->setCount(count($xactions)); - $crumbs = $this->buildApplicationCrumbs($this->buildSideNavView()); + $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb('Q'.$id, '/Q'.$id); $crumbs->setBorder(true); 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/src/applications/project/controller/PhabricatorProjectMembersAddController.php b/src/applications/project/controller/PhabricatorProjectMembersAddController.php index a3b89e46fd..79c66dc5b1 100644 --- a/src/applications/project/controller/PhabricatorProjectMembersAddController.php +++ b/src/applications/project/controller/PhabricatorProjectMembersAddController.php @@ -48,7 +48,7 @@ final class PhabricatorProjectMembersAddController '+' => array_fuse($member_phids), )); - $editor = id(new PhabricatorProjectTransactionEditor($project)) + $editor = id(new PhabricatorProjectTransactionEditor()) ->setActor($viewer) ->setContentSourceFromRequest($request) ->setContinueOnNoEffect(true) diff --git a/src/applications/project/controller/PhabricatorProjectMembersRemoveController.php b/src/applications/project/controller/PhabricatorProjectMembersRemoveController.php index ea41ea7113..029d4374b6 100644 --- a/src/applications/project/controller/PhabricatorProjectMembersRemoveController.php +++ b/src/applications/project/controller/PhabricatorProjectMembersRemoveController.php @@ -49,7 +49,7 @@ final class PhabricatorProjectMembersRemoveController '-' => array($remove_phid => $remove_phid), )); - $editor = id(new PhabricatorProjectTransactionEditor($project)) + $editor = id(new PhabricatorProjectTransactionEditor()) ->setActor($viewer) ->setContentSourceFromRequest($request) ->setContinueOnNoEffect(true) 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/src/applications/project/controller/PhabricatorProjectSilenceController.php b/src/applications/project/controller/PhabricatorProjectSilenceController.php index 6edd9bab39..ead0a83da2 100644 --- a/src/applications/project/controller/PhabricatorProjectSilenceController.php +++ b/src/applications/project/controller/PhabricatorProjectSilenceController.php @@ -53,7 +53,7 @@ final class PhabricatorProjectSilenceController $edge_action => array($viewer_phid => $viewer_phid), )); - $editor = id(new PhabricatorProjectTransactionEditor($project)) + $editor = id(new PhabricatorProjectTransactionEditor()) ->setActor($viewer) ->setContentSourceFromRequest($request) ->setContinueOnNoEffect(true) diff --git a/src/applications/project/controller/PhabricatorProjectUpdateController.php b/src/applications/project/controller/PhabricatorProjectUpdateController.php index 9f8c204c55..7cbd77b4cb 100644 --- a/src/applications/project/controller/PhabricatorProjectUpdateController.php +++ b/src/applications/project/controller/PhabricatorProjectUpdateController.php @@ -67,7 +67,7 @@ final class PhabricatorProjectUpdateController ->setMetadataValue('edge:type', $type_member) ->setNewValue($member_spec); - $editor = id(new PhabricatorProjectTransactionEditor($project)) + $editor = id(new PhabricatorProjectTransactionEditor()) ->setActor($viewer) ->setContentSourceFromRequest($request) ->setContinueOnNoEffect(true) diff --git a/src/applications/project/controller/PhabricatorProjectWatchController.php b/src/applications/project/controller/PhabricatorProjectWatchController.php index 00117768e1..cc83f782c6 100644 --- a/src/applications/project/controller/PhabricatorProjectWatchController.php +++ b/src/applications/project/controller/PhabricatorProjectWatchController.php @@ -64,7 +64,7 @@ final class PhabricatorProjectWatchController ->setMetadataValue('edge:type', $type_watcher) ->setNewValue($member_spec); - $editor = id(new PhabricatorProjectTransactionEditor($project)) + $editor = id(new PhabricatorProjectTransactionEditor()) ->setActor($viewer) ->setContentSourceFromRequest($request) ->setContinueOnNoEffect(true) diff --git a/src/applications/project/customfield/PhabricatorProjectConfiguredCustomField.php b/src/applications/project/customfield/PhabricatorProjectConfiguredCustomField.php index 6ee623147d..864aa76a24 100644 --- a/src/applications/project/customfield/PhabricatorProjectConfiguredCustomField.php +++ b/src/applications/project/customfield/PhabricatorProjectConfiguredCustomField.php @@ -11,9 +11,7 @@ final class PhabricatorProjectConfiguredCustomField public function createFields($object) { return PhabricatorStandardCustomField::buildStandardFields( $this, - PhabricatorEnv::getEnvConfig( - 'projects.custom-field-definitions', - array())); + PhabricatorEnv::getEnvConfig('projects.custom-field-definitions')); } } diff --git a/src/applications/project/icon/PhabricatorProjectIconSet.php b/src/applications/project/icon/PhabricatorProjectIconSet.php index 7e48cdfd74..2283026598 100644 --- a/src/applications/project/icon/PhabricatorProjectIconSet.php +++ b/src/applications/project/icon/PhabricatorProjectIconSet.php @@ -269,7 +269,7 @@ final class PhabricatorProjectIconSet 'The project icon ("%s") with special attribute "%s" must '. 'not be disabled', $key, - self::SPECIAL_MIILESTONE)); + self::SPECIAL_MILESTONE)); } $milestone = $value; } else { diff --git a/src/applications/releeph/query/ReleephRequestQuery.php b/src/applications/releeph/query/ReleephRequestQuery.php index 363a3b05d6..7d4f19e624 100644 --- a/src/applications/releeph/query/ReleephRequestQuery.php +++ b/src/applications/releeph/query/ReleephRequestQuery.php @@ -229,11 +229,11 @@ final class ReleephRequestQuery ); case self::STATUS_NEEDS_REVERT: return array( - ReleephRequestStatus::NEEDS_REVERT, + ReleephRequestStatus::STATUS_NEEDS_REVERT, ); case self::STATUS_REVERTED: return array( - ReleephRequestStatus::REVERTED, + ReleephRequestStatus::STATUS_REVERTED, ); default: throw new Exception(pht("Unknown status '%s'!", $this->status)); diff --git a/src/applications/repository/query/PhabricatorRepositoryURIQuery.php b/src/applications/repository/query/PhabricatorRepositoryURIQuery.php index 330fe769f5..71252a6fb7 100644 --- a/src/applications/repository/query/PhabricatorRepositoryURIQuery.php +++ b/src/applications/repository/query/PhabricatorRepositoryURIQuery.php @@ -30,11 +30,6 @@ final class PhabricatorRepositoryURIQuery return $this; } - public function withObjectHashes(array $hashes) { - $this->objectHashes = $hashes; - return $this; - } - public function newResultObject() { return new PhabricatorRepositoryURI(); } diff --git a/src/applications/repository/storage/PhabricatorRepositoryURI.php b/src/applications/repository/storage/PhabricatorRepositoryURI.php index 1cb3182c16..cbd25b74eb 100644 --- a/src/applications/repository/storage/PhabricatorRepositoryURI.php +++ b/src/applications/repository/storage/PhabricatorRepositoryURI.php @@ -577,7 +577,7 @@ final class PhabricatorRepositoryURI self::IO_READWRITE => 200, self::IO_READ => 100, ); - $score += idx($io_points, $this->getEffectiveIoType(), 0); + $score += idx($io_points, $this->getEffectiveIOType(), 0); $protocol_points = array( self::BUILTIN_PROTOCOL_SSH => 30, diff --git a/src/applications/search/controller/PhabricatorSearchHovercardController.php b/src/applications/search/controller/PhabricatorSearchHovercardController.php index 2fecf80dfd..ca83d1896d 100644 --- a/src/applications/search/controller/PhabricatorSearchHovercardController.php +++ b/src/applications/search/controller/PhabricatorSearchHovercardController.php @@ -11,6 +11,22 @@ final class PhabricatorSearchHovercardController $viewer = $this->getViewer(); $phids = $request->getArr('phids'); + // If object names are provided, look them up and pretend they were + // passed as additional PHIDs. This is primarily useful for debugging, + // since you don't have to go look up user PHIDs to preview their + // hovercards. + $names = $request->getStrList('names'); + if ($names) { + $named_objects = id(new PhabricatorObjectQuery()) + ->setViewer($viewer) + ->withNames($names) + ->execute(); + + foreach ($named_objects as $object) { + $phids[] = $object->getPHID(); + } + } + $handles = id(new PhabricatorHandleQuery()) ->setViewer($viewer) ->withPHIDs($phids) diff --git a/src/applications/search/engine/PhabricatorApplicationSearchEngine.php b/src/applications/search/engine/PhabricatorApplicationSearchEngine.php index d5ca8b7a5e..4329509b02 100644 --- a/src/applications/search/engine/PhabricatorApplicationSearchEngine.php +++ b/src/applications/search/engine/PhabricatorApplicationSearchEngine.php @@ -139,7 +139,7 @@ abstract class PhabricatorApplicationSearchEngine extends Phobject { * Executes the saved query. * * @param PhabricatorSavedQuery The saved query to operate on. - * @return The result of the query. + * @return PhabricatorQuery The result of the query. */ public function buildQueryFromSavedQuery(PhabricatorSavedQuery $original) { $saved = clone $original; @@ -469,7 +469,7 @@ abstract class PhabricatorApplicationSearchEngine extends Phobject { public function loadAllNamedQueries() { $viewer = $this->requireViewer(); - $builtin = $this->getBuiltinQueries($viewer); + $builtin = $this->getBuiltinQueries(); if ($this->namedQueries === null) { $named_queries = id(new PhabricatorNamedQueryQuery()) diff --git a/src/applications/search/engine/PhabricatorProfileMenuEngine.php b/src/applications/search/engine/PhabricatorProfileMenuEngine.php index f41424a4e7..4b24e67c6b 100644 --- a/src/applications/search/engine/PhabricatorProfileMenuEngine.php +++ b/src/applications/search/engine/PhabricatorProfileMenuEngine.php @@ -218,7 +218,7 @@ abstract class PhabricatorProfileMenuEngine extends Phobject { $edit_mode = $request->getURIData('itemEditMode'); } - $available_modes = $this->getViewerEditModes($viewer); + $available_modes = $this->getViewerEditModes(); if ($available_modes) { $available_modes = array_fuse($available_modes); if (isset($available_modes[$edit_mode])) { @@ -731,7 +731,7 @@ abstract class PhabricatorProfileMenuEngine extends Phobject { private function buildMenuEditModeContent() { $viewer = $this->getViewer(); - $modes = $this->getViewerEditModes($viewer); + $modes = $this->getViewerEditModes(); if (!$modes) { return new Aphront404Response(); } diff --git a/src/applications/search/menuitem/PhabricatorEditEngineProfileMenuItem.php b/src/applications/search/menuitem/PhabricatorEditEngineProfileMenuItem.php index 4b840d39e3..88749d247f 100644 --- a/src/applications/search/menuitem/PhabricatorEditEngineProfileMenuItem.php +++ b/src/applications/search/menuitem/PhabricatorEditEngineProfileMenuItem.php @@ -106,12 +106,14 @@ final class PhabricatorEditEngineProfileMenuItem if (!$form) { return array(); } - $engine = $form->getEngine(); - $form_key = $form->getIdentifier(); $icon = $form->getIcon(); $name = $this->getDisplayName($config); - $href = $engine->getEditURI(null, "form/{$form_key}/"); + + $href = $form->getCreateURI(); + if ($href === null) { + return array(); + } $item = $this->newItem() ->setHref($href) 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)]; + } + + +} diff --git a/src/applications/search/storage/PhabricatorSavedQuery.php b/src/applications/search/storage/PhabricatorSavedQuery.php index 5bc8a95915..3f75027888 100644 --- a/src/applications/search/storage/PhabricatorSavedQuery.php +++ b/src/applications/search/storage/PhabricatorSavedQuery.php @@ -59,8 +59,8 @@ final class PhabricatorSavedQuery extends PhabricatorSearchDAO return $this; } - public function getEvaluatedParameter($key, $default = null) { - return $this->assertAttachedKey($this->parameterMap, $key, $default); + public function getEvaluatedParameter($key) { + return $this->assertAttachedKey($this->parameterMap, $key); } 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/applications/slowvote/controller/PhabricatorSlowvoteVoteController.php b/src/applications/slowvote/controller/PhabricatorSlowvoteVoteController.php index 2d630bffc1..c69a825c3a 100644 --- a/src/applications/slowvote/controller/PhabricatorSlowvoteVoteController.php +++ b/src/applications/slowvote/controller/PhabricatorSlowvoteVoteController.php @@ -28,7 +28,7 @@ final class PhabricatorSlowvoteVoteController if ($request->isAjax()) { $vote = $request->getInt('vote'); $votes = array_keys($old_votes); - $votes = array_fuse($votes, $votes); + $votes = array_fuse($votes); if ($poll->getMethod() == PhabricatorSlowvotePoll::METHOD_PLURALITY) { if (idx($votes, $vote, false)) { @@ -68,7 +68,7 @@ final class PhabricatorSlowvoteVoteController } $votes = $request->getArr('vote'); - $votes = array_fuse($votes, $votes); + $votes = array_fuse($votes); $this->updateVotes($viewer, $poll, $old_votes, $votes); diff --git a/src/applications/spaces/controller/PhabricatorSpacesListController.php b/src/applications/spaces/controller/PhabricatorSpacesListController.php index fe439b0097..c270171574 100644 --- a/src/applications/spaces/controller/PhabricatorSpacesListController.php +++ b/src/applications/spaces/controller/PhabricatorSpacesListController.php @@ -9,7 +9,7 @@ final class PhabricatorSpacesListController public function handleRequest(AphrontRequest $request) { $request = $this->getRequest(); - $controller = id(new PhabricatorApplicationSearchController($request)) + $controller = id(new PhabricatorApplicationSearchController()) ->setQueryKey($request->getURIData('queryKey')) ->setSearchEngine(new PhabricatorSpacesNamespaceSearchEngine()) ->setNavigation($this->buildSideNavView()); diff --git a/src/applications/tokens/storage/PhabricatorTokensToken.php b/src/applications/tokens/storage/PhabricatorTokensToken.php index 8cd83cd884..50bada38b9 100644 --- a/src/applications/tokens/storage/PhabricatorTokensToken.php +++ b/src/applications/tokens/storage/PhabricatorTokensToken.php @@ -14,6 +14,7 @@ final class PhabricatorTokensToken extends PhabricatorTokenDAO protected $tokenImagePHID; protected $builtinKey; + private $tokenImageFile = self::ATTACHABLE; const STATUS_ACTIVE = 'active'; const STATUS_ARCHIVED = 'archived'; diff --git a/src/applications/transactions/editengine/PhabricatorEditEngine.php b/src/applications/transactions/editengine/PhabricatorEditEngine.php index e594ae4b67..eb4f607ca9 100644 --- a/src/applications/transactions/editengine/PhabricatorEditEngine.php +++ b/src/applications/transactions/editengine/PhabricatorEditEngine.php @@ -1489,8 +1489,7 @@ abstract class PhabricatorEditEngine ); } else { foreach ($configs as $config) { - $form_key = $config->getIdentifier(); - $config_uri = $this->getEditURI(null, "form/{$form_key}/"); + $config_uri = $config->getCreateURI(); if ($parameters) { $config_uri = (string)id(new PhutilURI($config_uri)) 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()); } diff --git a/src/applications/transactions/storage/PhabricatorEditEngineConfiguration.php b/src/applications/transactions/storage/PhabricatorEditEngineConfiguration.php index 457e9afca8..130686dd5a 100644 --- a/src/applications/transactions/storage/PhabricatorEditEngineConfiguration.php +++ b/src/applications/transactions/storage/PhabricatorEditEngineConfiguration.php @@ -216,6 +216,19 @@ final class PhabricatorEditEngineConfiguration return "/transactions/editengine/{$engine_key}/view/{$key}/"; } + public function getCreateURI() { + $form_key = $this->getIdentifier(); + $engine = $this->getEngine(); + + try { + $create_uri = $engine->getEditURI(null, "form/{$form_key}/"); + } catch (Exception $ex) { + $create_uri = null; + } + + return $create_uri; + } + public function getIdentifier() { $key = $this->getID(); if (!$key) { diff --git a/src/applications/transactions/typeahead/PhabricatorEditEngineDatasource.php b/src/applications/transactions/typeahead/PhabricatorEditEngineDatasource.php index ba1e693de8..6520ca6732 100644 --- a/src/applications/transactions/typeahead/PhabricatorEditEngineDatasource.php +++ b/src/applications/transactions/typeahead/PhabricatorEditEngineDatasource.php @@ -30,11 +30,17 @@ final class PhabricatorEditEngineDatasource $forms = $this->executeQuery($query); $results = array(); foreach ($forms as $form) { + $create_uri = $form->getCreateURI(); + if (!$create_uri) { + continue; + } + if ($form->getID()) { $key = $form->getEngineKey().'/'.$form->getID(); } else { $key = $form->getEngineKey().'/'.$form->getBuiltinKey(); } + $result = id(new PhabricatorTypeaheadResult()) ->setName($form->getName()) ->setPHID($key) diff --git a/src/applications/transactions/view/PhabricatorApplicationTransactionCommentView.php b/src/applications/transactions/view/PhabricatorApplicationTransactionCommentView.php index f69a2cd1bd..996b12bc51 100644 --- a/src/applications/transactions/view/PhabricatorApplicationTransactionCommentView.php +++ b/src/applications/transactions/view/PhabricatorApplicationTransactionCommentView.php @@ -12,6 +12,7 @@ class PhabricatorApplicationTransactionCommentView extends AphrontView { private $previewTimelineID; private $previewToggleID; private $formID; + private $statusID; private $commentID; private $draft; private $requestURI; 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. diff --git a/src/infrastructure/customfield/field/PhabricatorCustomField.php b/src/infrastructure/customfield/field/PhabricatorCustomField.php index 8f88c1469e..fba299fc8b 100644 --- a/src/infrastructure/customfield/field/PhabricatorCustomField.php +++ b/src/infrastructure/customfield/field/PhabricatorCustomField.php @@ -1095,7 +1095,7 @@ abstract class PhabricatorCustomField extends Phobject { public function getEditEngineFields(PhabricatorEditEngine $engine) { - $field = $this->newStandardEditField($engine); + $field = $this->newStandardEditField(); return array( $field, 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; + } + } diff --git a/src/infrastructure/daemon/bot/adapter/PhabricatorStreamingProtocolAdapter.php b/src/infrastructure/daemon/bot/adapter/PhabricatorStreamingProtocolAdapter.php index 52707b1a03..95955c1c2a 100644 --- a/src/infrastructure/daemon/bot/adapter/PhabricatorStreamingProtocolAdapter.php +++ b/src/infrastructure/daemon/bot/adapter/PhabricatorStreamingProtocolAdapter.php @@ -6,11 +6,11 @@ abstract class PhabricatorStreamingProtocolAdapter protected $readHandles; protected $multiHandle; protected $authtoken; + protected $inRooms = array(); private $readBuffers; private $server; private $active; - private $inRooms = array(); public function getServiceName() { $uri = new PhutilURI($this->server); 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/src/infrastructure/storage/lisk/LiskDAO.php b/src/infrastructure/storage/lisk/LiskDAO.php index 0527c3cf1e..c6712ae873 100644 --- a/src/infrastructure/storage/lisk/LiskDAO.php +++ b/src/infrastructure/storage/lisk/LiskDAO.php @@ -242,7 +242,7 @@ abstract class LiskDAO extends Phobject { * Get an existing, cached connection for this object. * * @param mode Connection mode. - * @return AprontDatabaseConnection|null Connection, if it exists in cache. + * @return AphrontDatabaseConnection|null Connection, if it exists in cache. * @task conn */ protected function getEstablishedConnection($mode) { @@ -953,7 +953,7 @@ abstract class LiskDAO extends Phobject { * @param string 'r' for read, 'w' for read/write. * @param bool True to force a new connection. The connection will not * be retrieved from or saved into the connection cache. - * @return LiskDatabaseConnection Lisk connection object. + * @return AphrontDatabaseConnection Lisk connection object. * * @task info */ diff --git a/src/infrastructure/util/password/PhabricatorPasswordHasher.php b/src/infrastructure/util/password/PhabricatorPasswordHasher.php index b7a4c1453b..7972acc0a8 100644 --- a/src/infrastructure/util/password/PhabricatorPasswordHasher.php +++ b/src/infrastructure/util/password/PhabricatorPasswordHasher.php @@ -260,7 +260,7 @@ abstract class PhabricatorPasswordHasher extends Phobject { /** * Get the best (strongest) available hasher. * - * @return PhabicatorPasswordHasher Best hasher. + * @return PhabricatorPasswordHasher Best hasher. * @task hashing */ public static function getBestHasher() { @@ -282,7 +282,7 @@ abstract class PhabricatorPasswordHasher extends Phobject { /** * Get the hashser for a given stored hash. * - * @return PhabicatorPasswordHasher Corresponding hasher. + * @return PhabricatorPasswordHasher Corresponding hasher. * @task hashing */ public static function getHasherForHash(PhutilOpaqueEnvelope $hash) { diff --git a/src/view/form/control/AphrontFormTextAreaControl.php b/src/view/form/control/AphrontFormTextAreaControl.php index 88eed462f3..2665c6aaa7 100644 --- a/src/view/form/control/AphrontFormTextAreaControl.php +++ b/src/view/form/control/AphrontFormTextAreaControl.php @@ -85,7 +85,7 @@ class AphrontFormTextAreaControl extends AphrontFormControl { array( 'name' => $this->getName(), 'disabled' => $this->getDisabled() ? 'disabled' : null, - 'readonly' => $this->getReadonly() ? 'readonly' : null, + 'readonly' => $this->getReadOnly() ? 'readonly' : null, 'class' => $classes, 'style' => $this->getControlStyle(), 'id' => $this->getID(), diff --git a/src/view/layout/AphrontSideNavFilterView.php b/src/view/layout/AphrontSideNavFilterView.php index 87c0d920e8..6564fab196 100644 --- a/src/view/layout/AphrontSideNavFilterView.php +++ b/src/view/layout/AphrontSideNavFilterView.php @@ -105,7 +105,7 @@ final class AphrontSideNavFilterView extends AphrontView { $key, $name, $uri, PHUIListItemView::TYPE_BUTTON); } - private function addThing($key, $name, $uri, $type, $icon) { + private function addThing($key, $name, $uri, $type, $icon = null) { $item = id(new PHUIListItemView()) ->setName($name) ->setType($type); 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, diff --git a/src/view/phui/PHUITimelineView.php b/src/view/phui/PHUITimelineView.php index fa3bd4a69f..20ce5e9e65 100644 --- a/src/view/phui/PHUITimelineView.php +++ b/src/view/phui/PHUITimelineView.php @@ -182,7 +182,7 @@ final class PHUITimelineView extends AphrontView { } if ($this->shouldTerminate) { - $events[] = self::renderEnder(true); + $events[] = self::renderEnder(); } return $events; diff --git a/src/view/phui/calendar/PHUICalendarDayView.php b/src/view/phui/calendar/PHUICalendarDayView.php index 5a2a8ee178..11ebc200e7 100644 --- a/src/view/phui/calendar/PHUICalendarDayView.php +++ b/src/view/phui/calendar/PHUICalendarDayView.php @@ -369,38 +369,4 @@ final class PHUICalendarDayView extends AphrontView { return $date; } - - private function findTodayClusters() { - $events = msort($this->todayEvents, 'getEpochStart'); - $clusters = array(); - - foreach ($events as $event) { - $destination_cluster_key = null; - $event_start = $event->getEpochStart() - (30 * 60); - $event_end = $event->getEpochEnd() + (30 * 60); - - foreach ($clusters as $key => $cluster) { - foreach ($cluster as $clustered_event) { - $compare_event_start = $clustered_event->getEpochStart(); - $compare_event_end = $clustered_event->getEpochEnd(); - - if ($event_start < $compare_event_end - && $event_end > $compare_event_start) { - $destination_cluster_key = $key; - break; - } - } - } - - if ($destination_cluster_key !== null) { - $clusters[$destination_cluster_key][] = $event; - } else { - $next_cluster = array(); - $next_cluster[] = $event; - $clusters[] = $next_cluster; - } - } - - return $clusters; - } } diff --git a/src/view/phui/calendar/PHUICalendarListView.php b/src/view/phui/calendar/PHUICalendarListView.php index bf4726796c..9ce03bcd84 100644 --- a/src/view/phui/calendar/PHUICalendarListView.php +++ b/src/view/phui/calendar/PHUICalendarListView.php @@ -57,7 +57,6 @@ final class PHUICalendarListView extends AphrontTagView { Javelin::initBehavior('phabricator-tooltips'); $singletons = array(); - $allday = false; foreach ($this->events as $event) { $start_epoch = $event->getEpochStart(); @@ -81,7 +80,7 @@ final class PHUICalendarListView extends AphrontTagView { array( 'class' => 'phui-calendar-list-title', ), - $this->getEventTitle($event, $allday)); + $this->getEventTitle($event)); $time = phutil_tag( 'span', array( 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/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, 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 { diff --git a/webroot/rsrc/css/application/dashboard/dashboard.css b/webroot/rsrc/css/application/dashboard/dashboard.css index d8f4d3450e..037dd227df 100644 --- a/webroot/rsrc/css/application/dashboard/dashboard.css +++ b/webroot/rsrc/css/application/dashboard/dashboard.css @@ -14,68 +14,109 @@ margin: 0 0 16px 0; } +.dashboard-box .phui-header-shell { + padding-top: 4px; + padding-bottom: 16px; +} + +.dashboard-box .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; } .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-box.phui-object-box { cursor: move; } -.aphront-multi-column-fluid -.aphront-multi-column-column .drag-ghost { +.grippable .aphront-multi-column-column .dashboard-box.phui-object-box:hover { + box-shadow: {$dropshadow}; +} + +.grippable .aphront-multi-column-column .dashboard-box.phui-object-box:hover + .dashboard-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/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/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 { 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/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; +} 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/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; } 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/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..874af5ee42 100644 --- a/webroot/rsrc/css/phui/phui-action-list.css +++ b/webroot/rsrc/css/phui/phui-action-list.css @@ -57,12 +57,18 @@ 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; display: block; text-decoration: none; color: {$darkbluetext}; + text-overflow: ellipsis; + overflow: hidden; } .action-has-icon button.phabricator-action-view-item, diff --git a/webroot/rsrc/css/phui/phui-basic-nav-view.css b/webroot/rsrc/css/phui/phui-basic-nav-view.css index 12605cc552..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; @@ -40,6 +36,7 @@ .phui-basic-nav.phui-navigation-shell .phabricator-nav-local { width: 205px; + max-width: 205px; padding-top: 12px; padding-right: 8px; } 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}; 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; 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); 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'); }