From b7a8c0b2000400aec9f60c0c827a46cbe975fa26 Mon Sep 17 00:00:00 2001 From: Ben Alpert Date: Mon, 26 May 2014 03:52:24 -0700 Subject: [PATCH 01/21] Fix references to `set-config --show` in docs Test Plan: Crossed many fingers. Reviewers: epriestley, #blessed_reviewers Reviewed By: epriestley, #blessed_reviewers Subscribers: epriestley, Korvin Differential Revision: https://secure.phabricator.com/D9298 --- src/docs/user/userguide/arcanist.diviner | 2 +- src/docs/user/userguide/arcanist_new_project.diviner | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/docs/user/userguide/arcanist.diviner b/src/docs/user/userguide/arcanist.diviner index 7f5d449526..b9c497007c 100644 --- a/src/docs/user/userguide/arcanist.diviner +++ b/src/docs/user/userguide/arcanist.diviner @@ -162,7 +162,7 @@ several sources: The first place where the setting is defined wins. -Existing settings can be printed with `arc set-config --show`. +Existing settings can be printed with `arc get-config`. == Next Steps == diff --git a/src/docs/user/userguide/arcanist_new_project.diviner b/src/docs/user/userguide/arcanist_new_project.diviner index c8f9389572..c29a53dfb4 100644 --- a/src/docs/user/userguide/arcanist_new_project.diviner +++ b/src/docs/user/userguide/arcanist_new_project.diviner @@ -74,7 +74,7 @@ These options are supported, but their use is discouraged: solution to certificate validity problems, and is discouraged. Instead, use valid certificates. -For a complete list of options, run `arc set-config --show`. Although all +For a complete list of options, run `arc get-config`. Although all options can be set in `.arcconfig`, some options (like `editor`) usually do not make sense to set here because they're likely to vary from user to user. From b93c2f68521d7d170cad3e9ff166f81d81ee03c7 Mon Sep 17 00:00:00 2001 From: epriestley Date: Mon, 26 May 2014 05:46:26 -0700 Subject: [PATCH 02/21] Fix two Passphrase credential type issues Summary: Fixes T4991. Two issues: - These error messages pass an object to "%s", when they mean to pass a type constant. - The check for noncreatable credentials is incorrectly in the "edit" branch of the controller. Test Plan: - Edited a "SSH Key on disk" credential. - Tried to create a credential with a bogus type. Reviewers: btrahan, joshuaspence Reviewed By: joshuaspence Subscribers: epriestley Maniphest Tasks: T4991 Differential Revision: https://secure.phabricator.com/D9299 --- .../PassphraseCredentialEditController.php | 32 +++++++++++-------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/src/applications/passphrase/controller/PassphraseCredentialEditController.php b/src/applications/passphrase/controller/PassphraseCredentialEditController.php index 063e8eca26..b8126cf476 100644 --- a/src/applications/passphrase/controller/PassphraseCredentialEditController.php +++ b/src/applications/passphrase/controller/PassphraseCredentialEditController.php @@ -26,23 +26,18 @@ final class PassphraseCredentialEditController extends PassphraseController { return new Aphront404Response(); } - $type = PassphraseCredentialType::getTypeByConstant( - $credential->getCredentialType()); - if (!$type) { - throw new Exception(pht('Credential has invalid type "%s"!', $type)); - } - - if (!$type->isCreateable()) { - throw new Exception( - pht('Credential has noncreateable type "%s"!', $type)); - } + $type = $this->getCredentialType($credential->getCredentialType()); $is_new = false; } else { $type_const = $request->getStr('type'); - $type = PassphraseCredentialType::getTypeByConstant($type_const); - if (!$type) { - return new Aphront404Response(); + $type = $this->getCredentialType($type_const); + + if (!$type->isCreateable()) { + throw new Exception( + pht( + 'Credential has noncreateable type "%s"!', + $credential->getCredentialType())); } $credential = PassphraseCredential::initializeNewCredential($viewer) @@ -358,4 +353,15 @@ final class PassphraseCredentialEditController extends PassphraseController { )); } + private function getCredentialType($type_const) { + $type = PassphraseCredentialType::getTypeByConstant($type_const); + + if (!$type) { + throw new Exception( + pht('Credential has invalid type "%s"!', $type_const)); + } + + return $type; + } + } From 607f4bfab8d188ac41d5025451fb059da8069880 Mon Sep 17 00:00:00 2001 From: lkassianik Date: Mon, 26 May 2014 11:15:28 -0700 Subject: [PATCH 03/21] Remove dedicated "Jump Nav" navigation element Summary: Fixes T5175. Not sure if I cleaned out everything, but this seemed like a reasonable first pass. Attempted to delete all code that belonged to Jump Nav feature only. Test Plan: Open phabricator homepage, verify Jump Nav element is gone, verify the Search bar still autocompletes and jumps to shortcuts. Reviewers: chad, epriestley, #blessed_reviewers Reviewed By: epriestley, #blessed_reviewers Subscribers: epriestley, Korvin Maniphest Tasks: T5175 Differential Revision: https://secure.phabricator.com/D9301 --- resources/celerity/map.php | 83 ++++++++-------- resources/celerity/packages.php | 2 - .../PhabricatorHomeMainController.php | 95 ------------------- .../directory/phabricator-jump-nav.css | 25 ----- 4 files changed, 40 insertions(+), 165 deletions(-) delete mode 100644 webroot/rsrc/css/application/directory/phabricator-jump-nav.css diff --git a/resources/celerity/map.php b/resources/celerity/map.php index 3e0eeef667..86fc00d4ce 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -7,7 +7,7 @@ return array( 'names' => array( - 'core.pkg.css' => '0d0b7e0c', + 'core.pkg.css' => 'c404fb89', 'core.pkg.js' => '7db41c19', 'darkconsole.pkg.js' => 'ca8671ce', 'differential.pkg.css' => 'fbf57382', @@ -64,7 +64,6 @@ return array( 'rsrc/css/application/diffusion/commit-view.css' => '92d1e8f9', 'rsrc/css/application/diffusion/diffusion-icons.css' => '384a0f7d', 'rsrc/css/application/diffusion/diffusion-source.css' => '66fdf661', - 'rsrc/css/application/directory/phabricator-jump-nav.css' => 'f0c5e726', 'rsrc/css/application/feed/feed.css' => 'dd43ce00', 'rsrc/css/application/files/global-drag-and-drop.css' => '697324ad', 'rsrc/css/application/flag/flag.css' => '5337623f', @@ -707,7 +706,6 @@ return array( 'phabricator-flag-css' => '5337623f', 'phabricator-hovercard' => '4f344388', 'phabricator-hovercard-view-css' => '46a13cf0', - 'phabricator-jump-nav' => 'f0c5e726', 'phabricator-keyboard-shortcut' => '1ae869f2', 'phabricator-keyboard-shortcut-manager' => 'ad7a69ca', 'phabricator-main-menu-view' => '0207239c', @@ -2114,46 +2112,45 @@ return array( 8 => 'aphront-tokenizer-control-css', 9 => 'aphront-typeahead-control-css', 10 => 'aphront-list-filter-view-css', - 11 => 'phabricator-jump-nav', - 12 => 'phabricator-remarkup-css', - 13 => 'syntax-highlighting-css', - 14 => 'aphront-pager-view-css', - 15 => 'phabricator-transaction-view-css', - 16 => 'aphront-tooltip-css', - 17 => 'phabricator-flag-css', - 18 => 'aphront-error-view-css', - 19 => 'sprite-remarkup-css', - 20 => 'sprite-gradient-css', - 21 => 'sprite-menu-css', - 22 => 'sprite-apps-large-css', - 23 => 'phabricator-main-menu-view', - 24 => 'phabricator-notification-css', - 25 => 'phabricator-notification-menu-css', - 26 => 'lightbox-attachment-css', - 27 => 'phui-header-view-css', - 28 => 'phabricator-filetree-view-css', - 29 => 'phabricator-nav-view-css', - 30 => 'phabricator-side-menu-view-css', - 31 => 'phabricator-crumbs-view-css', - 32 => 'phui-object-item-list-view-css', - 33 => 'global-drag-and-drop-css', - 34 => 'phui-spacing-css', - 35 => 'phui-form-css', - 36 => 'phui-icon-view-css', - 37 => 'phabricator-application-launch-view-css', - 38 => 'phabricator-action-list-view-css', - 39 => 'phui-property-list-view-css', - 40 => 'phui-tag-view-css', - 41 => 'phui-list-view-css', - 42 => 'font-fontawesome', - 43 => 'phui-font-icon-base-css', - 44 => 'sprite-main-header-css', - 45 => 'phui-box-css', - 46 => 'phui-object-box-css', - 47 => 'phui-timeline-view-css', - 48 => 'sprite-tokens-css', - 49 => 'tokens-css', - 50 => 'phui-status-list-view-css', + 11 => 'phabricator-remarkup-css', + 12 => 'syntax-highlighting-css', + 13 => 'aphront-pager-view-css', + 14 => 'phabricator-transaction-view-css', + 15 => 'aphront-tooltip-css', + 16 => 'phabricator-flag-css', + 17 => 'aphront-error-view-css', + 18 => 'sprite-remarkup-css', + 19 => 'sprite-gradient-css', + 20 => 'sprite-menu-css', + 21 => 'sprite-apps-large-css', + 22 => 'phabricator-main-menu-view', + 23 => 'phabricator-notification-css', + 24 => 'phabricator-notification-menu-css', + 25 => 'lightbox-attachment-css', + 26 => 'phui-header-view-css', + 27 => 'phabricator-filetree-view-css', + 28 => 'phabricator-nav-view-css', + 29 => 'phabricator-side-menu-view-css', + 30 => 'phabricator-crumbs-view-css', + 31 => 'phui-object-item-list-view-css', + 32 => 'global-drag-and-drop-css', + 33 => 'phui-spacing-css', + 34 => 'phui-form-css', + 35 => 'phui-icon-view-css', + 36 => 'phabricator-application-launch-view-css', + 37 => 'phabricator-action-list-view-css', + 38 => 'phui-property-list-view-css', + 39 => 'phui-tag-view-css', + 40 => 'phui-list-view-css', + 41 => 'font-fontawesome', + 42 => 'phui-font-icon-base-css', + 43 => 'sprite-main-header-css', + 44 => 'phui-box-css', + 45 => 'phui-object-box-css', + 46 => 'phui-timeline-view-css', + 47 => 'sprite-tokens-css', + 48 => 'tokens-css', + 49 => 'phui-status-list-view-css', ), 'core.pkg.js' => array( diff --git a/resources/celerity/packages.php b/resources/celerity/packages.php index 692099f2d5..e056c0c4ff 100644 --- a/resources/celerity/packages.php +++ b/resources/celerity/packages.php @@ -83,8 +83,6 @@ return array( 'aphront-typeahead-control-css', 'aphront-list-filter-view-css', - 'phabricator-jump-nav', - 'phabricator-remarkup-css', 'syntax-highlighting-css', 'aphront-pager-view-css', diff --git a/src/applications/home/controller/PhabricatorHomeMainController.php b/src/applications/home/controller/PhabricatorHomeMainController.php index adfad2863d..693695e300 100644 --- a/src/applications/home/controller/PhabricatorHomeMainController.php +++ b/src/applications/home/controller/PhabricatorHomeMainController.php @@ -16,10 +16,6 @@ final class PhabricatorHomeMainController public function processRequest() { $user = $this->getRequest()->getUser(); - - if ($this->filter == 'jump') { - return $this->buildJumpResponse(); - } $nav = $this->buildNav(); $dashboard = PhabricatorDashboardInstall::getDashboard( @@ -92,8 +88,6 @@ final class PhabricatorHomeMainController $welcome_panel = null; } - $jump_panel = $this->buildJumpPanel(); - if ($has_differential) { $revision_panel = $this->buildRevisionPanel(); } else { @@ -101,7 +95,6 @@ final class PhabricatorHomeMainController } $content = array( - $jump_panel, $welcome_panel, $unbreak_panel, $triage_panel, @@ -118,27 +111,6 @@ final class PhabricatorHomeMainController } - private function buildJumpResponse() { - $request = $this->getRequest(); - $jump = $request->getStr('jump'); - - $response = PhabricatorJumpNavHandler::getJumpResponse( - $request->getUser(), - $jump); - - if ($response) { - return $response; - } else if ($request->isFormPost()) { - $uri = new PhutilURI('/search/'); - $uri->setQueryParam('query', $jump); - $uri->setQueryParam('search:primary', 'true'); - - return id(new AphrontRedirectResponse())->setURI((string)$uri); - } else { - return id(new AphrontRedirectResponse())->setURI('/'); - } - } - private function buildUnbreakNowPanel() { $unbreak_now = PhabricatorEnv::getEnvConfig( 'maniphest.priorities.unbreak-now'); @@ -330,73 +302,6 @@ final class PhabricatorHomeMainController return $view; } - private function buildJumpPanel($query=null) { - $request = $this->getRequest(); - $user = $request->getUser(); - - $uniq_id = celerity_generate_unique_node_id(); - - Javelin::initBehavior( - 'phabricator-autofocus', - array( - 'id' => $uniq_id, - )); - - require_celerity_resource('phabricator-jump-nav'); - - $doc_href = PhabricatorEnv::getDocLink('Jump Nav User Guide'); - $doc_link = phutil_tag( - 'a', - array( - 'href' => $doc_href, - ), - 'Jump Nav User Guide'); - - $jump_input = phutil_tag( - 'input', - array( - 'type' => 'text', - 'class' => 'phabricator-jump-nav', - 'name' => 'jump', - 'id' => $uniq_id, - 'value' => $query, - )); - $jump_caption = phutil_tag( - 'p', - array( - 'class' => 'phabricator-jump-nav-caption', - ), - hsprintf( - 'Enter the name of an object like D123 to quickly jump to '. - 'it. See %s or type help.', - $doc_link)); - - $form = phabricator_form( - $user, - array( - 'action' => '/jump/', - 'method' => 'POST', - 'class' => 'phabricator-jump-nav-form', - ), - array( - $jump_input, - $jump_caption, - )); - - $panel = new AphrontPanelView(); - $panel->setNoBackground(); - // $panel->appendChild(); - - $list_filter = new AphrontListFilterView(); - $list_filter->appendChild($form); - - $container = phutil_tag('div', - array('class' => 'phabricator-jump-nav-container'), - $list_filter); - - return $container; - } - private function renderSectionHeader($title, $href) { $header = phutil_tag( 'a', diff --git a/webroot/rsrc/css/application/directory/phabricator-jump-nav.css b/webroot/rsrc/css/application/directory/phabricator-jump-nav.css deleted file mode 100644 index fe06c4c973..0000000000 --- a/webroot/rsrc/css/application/directory/phabricator-jump-nav.css +++ /dev/null @@ -1,25 +0,0 @@ -/** - * @provides phabricator-jump-nav - */ - -.phabricator-jump-nav-form { - text-align: center; - padding: 0px; - margin: 0; -} - -input.phabricator-jump-nav[type='text'] { - font-size: 16px; - width: 100%; -} - -.phabricator-jump-nav-caption { - margin-top: 4px; - font-size: 11px; - color: {$greytext}; - text-align: left; -} - -.phabricator-jump-nav-container form { - padding: 12px 16px; -} From 1daa0aa36e264e9b08b68570abab099f512ad573 Mon Sep 17 00:00:00 2001 From: Joshua Spence Date: Tue, 27 May 2014 06:14:06 -0700 Subject: [PATCH 04/21] Syntax highlight `.arclint` files as JSON. Summary: After T2039, it makes sense to syntax highlight `.arclint` files as JSON. Test Plan: N/A Reviewers: epriestley, #blessed_reviewers Reviewed By: epriestley, #blessed_reviewers Subscribers: epriestley, Korvin Differential Revision: https://secure.phabricator.com/D9305 --- conf/default.conf.php | 1 + .../config/option/PhabricatorSyntaxHighlightingConfigOptions.php | 1 + 2 files changed, 2 insertions(+) diff --git a/conf/default.conf.php b/conf/default.conf.php index 7cef111ba1..e2f913c3aa 100644 --- a/conf/default.conf.php +++ b/conf/default.conf.php @@ -1035,6 +1035,7 @@ return array( // '@\\.([^.]+)\\.bak$@' => 1, '@\.arcconfig$@' => 'js', + '@\.arclint$@' => 'js', '@\.divinerconfig$@' => 'js', ), diff --git a/src/applications/config/option/PhabricatorSyntaxHighlightingConfigOptions.php b/src/applications/config/option/PhabricatorSyntaxHighlightingConfigOptions.php index d0fcc26df6..d810a155c7 100644 --- a/src/applications/config/option/PhabricatorSyntaxHighlightingConfigOptions.php +++ b/src/applications/config/option/PhabricatorSyntaxHighlightingConfigOptions.php @@ -77,6 +77,7 @@ final class PhabricatorSyntaxHighlightingConfigOptions 'wild', array( '@\.arcconfig$@' => 'js', + '@\.arclint$@' => 'js', '@\.divinerconfig$@' => 'js', )) ->setSummary( From 33aa395806522e9d642948e79682266e0fd85ed1 Mon Sep 17 00:00:00 2001 From: epriestley Date: Tue, 27 May 2014 13:44:21 -0700 Subject: [PATCH 05/21] Delete some junko garbage Summary: We haven't needed this for like three years, so we probably won't ever need it. It's in history if we do. Test Plan: thought long and hard Reviewers: btrahan, chad Reviewed By: chad Subscribers: epriestley Differential Revision: https://secure.phabricator.com/D9311 --- .../plugin/DarkConsoleErrorLogPlugin.php | 55 ------------------- 1 file changed, 55 deletions(-) diff --git a/src/aphront/console/plugin/DarkConsoleErrorLogPlugin.php b/src/aphront/console/plugin/DarkConsoleErrorLogPlugin.php index 7c96cafe6f..cf2d2841f2 100644 --- a/src/aphront/console/plugin/DarkConsoleErrorLogPlugin.php +++ b/src/aphront/console/plugin/DarkConsoleErrorLogPlugin.php @@ -99,58 +99,3 @@ final class DarkConsoleErrorLogPlugin extends DarkConsolePlugin { )); } } - -/* - $data = $this->getData(); - if (!$data) { - return - -
No errors.
-
; - } - - $markup = ; - $alt = false; - foreach ($data as $error) { - $row = ; - - $text = $error['error']; - $text = preg_replace('/\(in .* on line \d+\)$/', '', trim($text)); - - $trace = $error['trace']; - $trace = explode("\n", $trace); - if (!$trace) { - $trace = array('unknown@0@unknown'); - } - - foreach ($trace as $idx => $traceline) { - list($file, $line, $where) = array_merge( - explode('@', $traceline), - array('?', '?', '?')); - if ($where == 'DarkConsole->addError' || - $where == 'debug_rlog') { - unset($trace[$idx]); - } - } - - $row->appendChild(); - - foreach ($trace as $traceline) { - list($file, $line, $where) = array_merge( - explode('@', $traceline), - array('?', '?', '?')); - $row->appendChild(); - $row->appendChild(); - $markup->appendChild($row); - $row = ; - } - - $alt = !$alt; - } - - return - -

Errors

-
{$markup}
-
; -*/ From 92ccadaa42d2d91314c051a08756f9012927af3a Mon Sep 17 00:00:00 2001 From: lkassianik Date: Tue, 27 May 2014 15:34:41 -0700 Subject: [PATCH 06/21] Create an empty state for dashboards Summary: Fixes T5177. Not sure if checking for panelPHIDs is right, but seemed like a better choice than adding a new property on dashboard. Test Plan: Create dashboard with no panels. Go to view dashboard. "view" page should have a placeholder that directs user to Manage Dashboard Reviewers: epriestley, #blessed_reviewers Reviewed By: epriestley, #blessed_reviewers Subscribers: epriestley, Korvin Maniphest Tasks: T5177 Differential Revision: https://secure.phabricator.com/D9312 --- .../PhabricatorDashboardViewController.php | 29 +++++++++++++++---- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/src/applications/dashboard/controller/PhabricatorDashboardViewController.php b/src/applications/dashboard/controller/PhabricatorDashboardViewController.php index 5fded53dab..0201a8e2ee 100644 --- a/src/applications/dashboard/controller/PhabricatorDashboardViewController.php +++ b/src/applications/dashboard/controller/PhabricatorDashboardViewController.php @@ -26,10 +26,14 @@ final class PhabricatorDashboardViewController $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb(pht('Dashboard %d', $dashboard->getID())); - $rendered_dashboard = id(new PhabricatorDashboardRenderingEngine()) - ->setViewer($viewer) - ->setDashboard($dashboard) - ->renderDashboard(); + if ($dashboard->getPanelPHIDs()) { + $rendered_dashboard = id(new PhabricatorDashboardRenderingEngine()) + ->setViewer($viewer) + ->setDashboard($dashboard) + ->renderDashboard(); + } else { + $rendered_dashboard = $this->buildEmptyView(); + } return $this->buildApplicationPage( array( @@ -50,9 +54,24 @@ final class PhabricatorDashboardViewController id(new PHUIListItemView()) ->setIcon('fa-th') ->setName(pht('Manage Dashboard')) - ->setHref($this->getApplicationURI()."manage/{$id}/")); + ->setHref($this->getApplicationURI("manage/{$id}/"))); return $crumbs; } + public function buildEmptyView() { + $id = $this->id; + $manage_uri = $this->getApplicationURI("manage/{$id}/"); + + return id(new AphrontErrorView()) + ->setSeverity(AphrontErrorView::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')))); + } + } From 70ec8052fddcb2d002e7b0b8e0dbd0977d5f8357 Mon Sep 17 00:00:00 2001 From: epriestley Date: Tue, 27 May 2014 17:21:34 -0700 Subject: [PATCH 07/21] Fix issue when editing a project with no secondary hash tags Summary: Fixes T5186. If a project has no secondary tags, we issue a bogus query right now. Test Plan: Edited a project with no secondary tags. Reviewers: btrahan, chad Reviewed By: chad Subscribers: epriestley Maniphest Tasks: T5186 Differential Revision: https://secure.phabricator.com/D9300 --- .../editor/PhabricatorProjectTransactionEditor.php | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/applications/project/editor/PhabricatorProjectTransactionEditor.php b/src/applications/project/editor/PhabricatorProjectTransactionEditor.php index 27b0c4a13d..a1312bac20 100644 --- a/src/applications/project/editor/PhabricatorProjectTransactionEditor.php +++ b/src/applications/project/editor/PhabricatorProjectTransactionEditor.php @@ -305,8 +305,15 @@ final class PhabricatorProjectTransactionEditor $slug_xaction = last($xactions); $new = $slug_xaction->getNewValue(); - $slugs_used_already = id(new PhabricatorProjectSlug()) - ->loadAllWhere('slug IN (%Ls)', $new); + + if ($new) { + $slugs_used_already = id(new PhabricatorProjectSlug()) + ->loadAllWhere('slug IN (%Ls)', $new); + } else { + // The project doesn't have any extra slugs. + $slugs_used_already = array(); + } + $slugs_used_already = mgroup($slugs_used_already, 'getProjectPHID'); foreach ($slugs_used_already as $project_phid => $used_slugs) { $used_slug_strs = mpull($used_slugs, 'getSlug'); From 71d2b0868b73bb3f43035d9ce19c94067ba6da83 Mon Sep 17 00:00:00 2001 From: Stepan Generalov Date: Tue, 27 May 2014 17:23:08 -0700 Subject: [PATCH 08/21] Fix typo: behvaior->behavior See: Reviewed by: epriestley --- .../differential/customfield/DifferentialTestPlanField.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/applications/differential/customfield/DifferentialTestPlanField.php b/src/applications/differential/customfield/DifferentialTestPlanField.php index c4c8cf7943..efc3bfc1a0 100644 --- a/src/applications/differential/customfield/DifferentialTestPlanField.php +++ b/src/applications/differential/customfield/DifferentialTestPlanField.php @@ -44,7 +44,7 @@ final class DifferentialTestPlanField protected function getCoreFieldRequiredErrorString() { return pht( 'You must provide a test plan. Describe the actions you performed '. - 'to verify the behvaior of this change.'); + 'to verify the behavior of this change.'); } public function readValueFromRequest(AphrontRequest $request) { From 2aef04a78afb62b0532ef8f2f8efb229d6abeabc Mon Sep 17 00:00:00 2001 From: epriestley Date: Tue, 27 May 2014 17:37:26 -0700 Subject: [PATCH 09/21] Fix Diffusion blame/highlight for logged-out users Summary: Fixes T5199. We try to save these options in user preferences, but logged-out users don't have preferences. Instead, just use GET links for logged-out users. Test Plan: - As a logged-out user, toggled blame and highlight on and off. - As a logged-in user, toggled blame and highlight on and off. Reviewers: btrahan, vrana Reviewed By: vrana Subscribers: epriestley Maniphest Tasks: T5199 Differential Revision: https://secure.phabricator.com/D9310 --- .../controller/DiffusionBrowseFileController.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/applications/diffusion/controller/DiffusionBrowseFileController.php b/src/applications/diffusion/controller/DiffusionBrowseFileController.php index fdeeabdb56..2a926136a8 100644 --- a/src/applications/diffusion/controller/DiffusionBrowseFileController.php +++ b/src/applications/diffusion/controller/DiffusionBrowseFileController.php @@ -9,6 +9,7 @@ final class DiffusionBrowseFileController extends DiffusionBrowseController { public function processRequest() { $request = $this->getRequest(); $drequest = $this->getDiffusionRequest(); + $viewer = $request->getUser(); $before = $request->getStr('before'); if ($before) { @@ -17,7 +18,7 @@ final class DiffusionBrowseFileController extends DiffusionBrowseController { $path = $drequest->getPath(); - $preferences = $request->getUser()->loadPreferences(); + $preferences = $viewer->loadPreferences(); $show_blame = $request->getBool( 'blame', @@ -31,7 +32,7 @@ final class DiffusionBrowseFileController extends DiffusionBrowseController { true)); $view = $request->getStr('view'); - if ($request->isFormPost() && $view != 'raw') { + if ($request->isFormPost() && $view != 'raw' && $viewer->isLoggedIn()) { $preferences->setPreference( PhabricatorUserPreferences::PREFERENCE_DIFFUSION_BLAME, $show_blame); @@ -354,7 +355,7 @@ final class DiffusionBrowseFileController extends DiffusionBrowseController { ->setHref($base_uri->alter('blame', $blame_value)) ->setIcon($blame_icon) ->setUser($viewer) - ->setRenderAsForm(true)); + ->setRenderAsForm($viewer->isLoggedIn())); if ($show_color) { $highlight_text = pht('Disable Highlighting'); @@ -372,7 +373,7 @@ final class DiffusionBrowseFileController extends DiffusionBrowseController { ->setHref($base_uri->alter('color', $highlight_value)) ->setIcon($highlight_icon) ->setUser($viewer) - ->setRenderAsForm(true)); + ->setRenderAsForm($viewer->isLoggedIn())); $href = null; if ($this->getRequest()->getStr('lint') !== null) { From 1855e66758687d6871a744c632fe970cdf18440d Mon Sep 17 00:00:00 2001 From: Joshua Spence Date: Wed, 28 May 2014 06:26:20 -0700 Subject: [PATCH 10/21] Add some file types to `pygments.dropdown-choices`. Summary: I could just add these options to my local configuration, but I figured I'd submit these upstream since they are (in my opinion) fairly common file formats. Test Plan: N/A Reviewers: epriestley, #blessed_reviewers Reviewed By: epriestley, #blessed_reviewers Subscribers: epriestley, Korvin Differential Revision: https://secure.phabricator.com/D9319 --- conf/default.conf.php | 6 ++++++ .../option/PhabricatorSyntaxHighlightingConfigOptions.php | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/conf/default.conf.php b/conf/default.conf.php index e2f913c3aa..e441e130da 100644 --- a/conf/default.conf.php +++ b/conf/default.conf.php @@ -992,6 +992,7 @@ return array( 'bash' => 'Bash Scripting', 'brainfuck' => 'Brainf*ck', 'c' => 'C', + 'coffee-script' => 'CoffeeScript', 'cpp' => 'C++', 'css' => 'CSS', 'd' => 'D', @@ -999,14 +1000,18 @@ return array( 'django' => 'Django Templating', 'erb' => 'Embedded Ruby/ERB', 'erlang' => 'Erlang', + 'go' => 'Golang', + 'groovy' => 'Groovy', 'haskell' => 'Haskell', 'html' => 'HTML', 'java' => 'Java', 'js' => 'Javascript', + 'json' => 'JSON', 'mysql' => 'MySQL', 'objc' => 'Objective-C', 'perl' => 'Perl', 'php' => 'PHP', + 'puppet' => 'Puppet', 'rest' => 'reStructuredText', 'text' => 'Plain Text', 'python' => 'Python', @@ -1014,6 +1019,7 @@ return array( 'remarkup' => 'Remarkup', 'ruby' => 'Ruby', 'xml' => 'XML', + 'yaml' => 'YAML', ), // This is an override list of regular expressions which allows you to choose diff --git a/src/applications/config/option/PhabricatorSyntaxHighlightingConfigOptions.php b/src/applications/config/option/PhabricatorSyntaxHighlightingConfigOptions.php index d810a155c7..4ce4725faa 100644 --- a/src/applications/config/option/PhabricatorSyntaxHighlightingConfigOptions.php +++ b/src/applications/config/option/PhabricatorSyntaxHighlightingConfigOptions.php @@ -42,6 +42,7 @@ final class PhabricatorSyntaxHighlightingConfigOptions 'bash' => 'Bash Scripting', 'brainfuck' => 'Brainf*ck', 'c' => 'C', + 'coffee-script' => 'CoffeeScript', 'cpp' => 'C++', 'css' => 'CSS', 'd' => 'D', @@ -49,15 +50,19 @@ final class PhabricatorSyntaxHighlightingConfigOptions 'django' => 'Django Templating', 'erb' => 'Embedded Ruby/ERB', 'erlang' => 'Erlang', + 'go' => 'Golang', + 'groovy' => 'Groovy', 'haskell' => 'Haskell', 'html' => 'HTML', 'invisible' => 'Invisible', 'java' => 'Java', 'js' => 'Javascript', + 'json' => 'JSON', 'mysql' => 'MySQL', 'objc' => 'Objective-C', 'perl' => 'Perl', 'php' => 'PHP', + 'puppet' => 'Puppet', 'rest' => 'reStructuredText', 'text' => 'Plain Text', 'python' => 'Python', @@ -65,6 +70,7 @@ final class PhabricatorSyntaxHighlightingConfigOptions 'remarkup' => 'Remarkup', 'ruby' => 'Ruby', 'xml' => 'XML', + 'yaml' => 'YAML', )) ->setSummary( pht("Set the language list which appears in dropdowns.")) From c7a7574f0c8edfa7b9ce3daaa3cd340a56b25fe0 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Wed, 28 May 2014 11:18:28 -0700 Subject: [PATCH 11/21] Remove oneline feed story Summary: People seem confused and it is a little inconsistent. Also added other app icon types. Test Plan: Viewed a number of feed stories. Reviewers: epriestley Reviewed By: epriestley Subscribers: epriestley, Korvin Differential Revision: https://secure.phabricator.com/D9320 --- src/view/phui/PHUIFeedStoryView.php | 48 +++++++++++------------------ 1 file changed, 18 insertions(+), 30 deletions(-) diff --git a/src/view/phui/PHUIFeedStoryView.php b/src/view/phui/PHUIFeedStoryView.php index c1b4df9cb2..5fc8745474 100644 --- a/src/view/phui/PHUIFeedStoryView.php +++ b/src/view/phui/PHUIFeedStoryView.php @@ -142,7 +142,6 @@ final class PHUIFeedStoryView extends AphrontView { require_celerity_resource('phui-feed-story-css'); Javelin::initBehavior('phabricator-hovercards'); - $oneline = !$this->hasChildren(); $body = null; $foot = null; @@ -186,18 +185,6 @@ final class PHUIFeedStoryView extends AphrontView { $icon->setSpriteSheet(PHUIIconView::SPRITE_APPS); } - $ol_foot = null; - if ($oneline) { - $ol_foot = phutil_tag( - 'div', - array( - 'class' => 'phui-feed-story-oneline-foot' - ), - array( - $icon, - $foot)); - } - $action_list = array(); $icons = null; foreach ($this->actions as $action) { @@ -223,10 +210,9 @@ final class PHUIFeedStoryView extends AphrontView { 'class' => 'phui-feed-story-head', ), array( - (!$oneline ? $actor : null), + $actor, nonempty($this->title, pht('Untitled Story')), $icons, - $ol_foot )); if (!empty($this->tokenBar)) { @@ -249,23 +235,16 @@ final class PHUIFeedStoryView extends AphrontView { $body_content); } - if ($oneline) { - $foot = null; - } else { - $foot = phutil_tag( - 'div', - array( - 'class' => 'phui-feed-story-foot', - ), - array( - $icon, - $foot)); - } + $foot = phutil_tag( + 'div', + array( + 'class' => 'phui-feed-story-foot', + ), + array( + $icon, + $foot)); $classes = array('phui-feed-story'); - if ($oneline) { - $classes[] = 'phui-feed-story-oneline'; - } return id(new PHUIBoxView()) ->addClass(implode(' ', $classes)) @@ -282,6 +261,15 @@ final class PHUIFeedStoryView extends AphrontView { case PhabricatorMacroPHIDTypeMacro::TYPECONST: $this->setAppIcon("macro-dark"); break; + case ManiphestPHIDTypeTask::TYPECONST: + $this->setAppIcon('maniphest-dark'); + break; + case DifferentialPHIDTypeRevision::TYPECONST: + $this->setAppIcon('differential-dark'); + break; + case PhabricatorCalendarPHIDTypeEvent::TYPECONST: + $this->setAppIcon('calendar-dark'); + break; } } } From dd3dfde98360d68640a5395680e415dd596850ff Mon Sep 17 00:00:00 2001 From: Chad Horohoe Date: Wed, 28 May 2014 15:36:27 -0700 Subject: [PATCH 12/21] T4446: Fix Elasticsearch support for 1.0 and above Summary: Elasticsearch 1.0 deprecated the "filter" top-level parameter in favor of "post_filter" which is applied after scores and so forth are calculated. Instead search field.corpus with a term query. Test Plan: Tested against Elasticsearch 1.1.1, able to perform basic queries without query parse errors. Reviewers: epriestley, #blessed_reviewers Reviewed By: epriestley, #blessed_reviewers Subscribers: epriestley, Korvin Maniphest Tasks: T4446 Differential Revision: https://secure.phabricator.com/D9321 --- .../search/engine/PhabricatorSearchEngineElastic.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/applications/search/engine/PhabricatorSearchEngineElastic.php b/src/applications/search/engine/PhabricatorSearchEngineElastic.php index 120460a6c0..82e03cf350 100644 --- a/src/applications/search/engine/PhabricatorSearchEngineElastic.php +++ b/src/applications/search/engine/PhabricatorSearchEngineElastic.php @@ -97,7 +97,7 @@ final class PhabricatorSearchEngineElastic extends PhabricatorSearchEngine { if (strlen($query->getParameter('query'))) { $spec[] = array( - 'field' => array( + 'term' => array( 'field.corpus' => $query->getParameter('query'), ), ); From b20142c0febe40c65cc9113cdab3d8dc4cfd7dde Mon Sep 17 00:00:00 2001 From: James Rhodes Date: Thu, 29 May 2014 05:45:14 -0700 Subject: [PATCH 13/21] Fix PhabricatorPolicyDataTestCase Summary: Fixes T5219. Test Plan: Ran `arc unit`. Reviewers: epriestley, #blessed_reviewers Reviewed By: epriestley, #blessed_reviewers Subscribers: epriestley, Korvin Maniphest Tasks: T5219 Differential Revision: https://secure.phabricator.com/D9326 --- .../policy/__tests__/PhabricatorPolicyDataTestCase.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/applications/policy/__tests__/PhabricatorPolicyDataTestCase.php b/src/applications/policy/__tests__/PhabricatorPolicyDataTestCase.php index 89b303b0d9..e0f66c1569 100644 --- a/src/applications/policy/__tests__/PhabricatorPolicyDataTestCase.php +++ b/src/applications/policy/__tests__/PhabricatorPolicyDataTestCase.php @@ -14,10 +14,12 @@ final class PhabricatorPolicyDataTestCase extends PhabricatorTestCase { $proj_a = id(new PhabricatorProject()) ->setName('A') ->setAuthorPHID($author->getPHID()) + ->setIcon('fa-briefcase') ->save(); $proj_b = id(new PhabricatorProject()) ->setName('B') ->setAuthorPHID($author->getPHID()) + ->setIcon('fa-briefcase') ->save(); $proj_a->setViewPolicy($proj_b->getPHID())->save(); From 7f2b6412a2e844692571647e2961c3a31b5180d7 Mon Sep 17 00:00:00 2001 From: epriestley Date: Thu, 29 May 2014 06:44:45 -0700 Subject: [PATCH 14/21] Fix an issue with Phrequent where range_start might not be defined Summary: If two events start on the same second (somewhat common now, since start time can be specified) we'll hit a "push" with no range start. Instead, always set a minimal range start. --- src/applications/phrequent/storage/PhrequentTimeBlock.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/applications/phrequent/storage/PhrequentTimeBlock.php b/src/applications/phrequent/storage/PhrequentTimeBlock.php index 60721e45ca..45b3555fd2 100644 --- a/src/applications/phrequent/storage/PhrequentTimeBlock.php +++ b/src/applications/phrequent/storage/PhrequentTimeBlock.php @@ -23,6 +23,11 @@ final class PhrequentTimeBlock extends Phobject { public function getObjectTimeRanges($now) { $ranges = array(); + $range_start = time(); + foreach ($this->events as $event) { + $range_start = min($range_start, $event->getDateStarted()); + } + $object_ranges = array(); foreach ($this->events as $event) { From a42ec32c98b6e33d0adef68ec02ca891d5d1658b Mon Sep 17 00:00:00 2001 From: Joshua Spence Date: Thu, 29 May 2014 07:04:12 -0700 Subject: [PATCH 15/21] Modify the Aphlict client to use `LocalConnection`. Summary: Ref T4324. Currently, an Aphlict client (with a corresponding connection to the Aphlict Server) is created for every tab that a user has open. This significantly affects the scalability of Aphlict as a service. Instead, we can use `LocalConnection` instances to coordinate the communication of multiple Aphlict clients to the server. Similar functionality existed prior to D2704, but was removed as the author was not able to get this functionality working as intended. It seems that the main issue with the initial attempt was the use of the `setTimeout` function, which seemed to be a blocking call which prevented messages from being received. I have instead used an event-based model using a `Timer` object. Roughly this works as follows: # The first instance will create an `AphlictClient` and an `AphlictMaster`. The `AphlictClient` will register itself with the `AphlictMaster` and will consequently be notified of incoming messages. # The `AphlictClient` is then responsible for pinging the `AphlictMaster` at regular intervals. If the client does not ping the master in a given period of time, the master will assume that the client is dead and will remove the client from the pool. # Similarly, the `AphlictMaster` is required to respond to pings with a "pong" response. The pong response lets the clients know that the `AphlictMaster` is still alive. If the clients do not receive a pong in a given period of time, then the clients will attempt to spawn a new master. Test Plan: I have tested this on our Phabricator install with a few tabs opened and inspecting the console output. I will upload a screencast of my test results. Reviewers: #blessed_reviewers, epriestley Reviewed By: #blessed_reviewers, epriestley Subscribers: epriestley, Korvin Maniphest Tasks: T4324 Differential Revision: https://secure.phabricator.com/D9327 --- .../aphlict/client/build_aphlict_client.sh | 13 +- support/aphlict/client/src/Aphlict.as | 113 ++---------- support/aphlict/client/src/AphlictClient.as | 129 ++++++++++++++ support/aphlict/client/src/AphlictMaster.as | 166 ++++++++++++++++++ webroot/rsrc/swf/aphlict.swf | Bin 7217 -> 9213 bytes 5 files changed, 315 insertions(+), 106 deletions(-) create mode 100644 support/aphlict/client/src/AphlictClient.as create mode 100644 support/aphlict/client/src/AphlictMaster.as diff --git a/support/aphlict/client/build_aphlict_client.sh b/support/aphlict/client/build_aphlict_client.sh index b328873d19..f081c9f0d2 100755 --- a/support/aphlict/client/build_aphlict_client.sh +++ b/support/aphlict/client/build_aphlict_client.sh @@ -9,20 +9,13 @@ if [ -z "$MXMLC" ]; then fi; set -e -set -x -# cp -R $ROOT/externals/vegas/src $BASEDIR/src/vegas - -(cd $BASEDIR && $MXMLC \ - -output aphlict.swf \ +$MXMLC \ + -output=$ROOT/webroot/rsrc/swf/aphlict.swf \ -default-background-color=0x444444 \ -default-size=500,500 \ -warnings=true \ -debug=true \ -source-path=$ROOT/externals/vegas/src \ -static-link-runtime-shared-libraries=true \ - src/Aphlict.as) - -mv $BASEDIR/aphlict.swf $ROOT/webroot/rsrc/swf/aphlict.swf - -# -target-player=10.2.0 \ + $BASEDIR/src/AphlictClient.as diff --git a/support/aphlict/client/src/Aphlict.as b/support/aphlict/client/src/Aphlict.as index 14eb9548db..d61ad04b0a 100644 --- a/support/aphlict/client/src/Aphlict.as +++ b/support/aphlict/client/src/Aphlict.as @@ -1,117 +1,38 @@ package { - import flash.net.*; - import flash.utils.*; - import flash.media.*; - import flash.display.*; - import flash.events.*; + import flash.display.Sprite; import flash.external.ExternalInterface; + import flash.net.LocalConnection; - import vegas.strings.JSON; public class Aphlict extends Sprite { - private var client:String; + /** + * A transport channel used to receive data. + */ + protected var recv:LocalConnection; - private var socket:Socket; - private var readBuffer:ByteArray; + /** + * A transport channel used to send data. + */ + protected var send:LocalConnection; - private var remoteServer:String; - private var remotePort:Number; public function Aphlict() { super(); - ExternalInterface.addCallback('connect', this.externalConnect); - ExternalInterface.call( - 'JX.Stratcom.invoke', - 'aphlict-component-ready', - null, - {}); + this.recv = new LocalConnection(); + this.recv.client = this; + + this.send = new LocalConnection(); } - public function externalConnect(server:String, port:Number):void { - this.externalInvoke('connect'); - - this.remoteServer = server; - this.remotePort = port; - - this.connectToServer(); - } - - - public function connectToServer():void { - var socket:Socket = new Socket(); - - socket.addEventListener(Event.CONNECT, didConnectSocket); - socket.addEventListener(Event.CLOSE, didCloseSocket); - socket.addEventListener(ProgressEvent.SOCKET_DATA, didReceiveSocket); - - socket.addEventListener(IOErrorEvent.IO_ERROR, didIOErrorSocket); - socket.addEventListener( - SecurityErrorEvent.SECURITY_ERROR, - didSecurityErrorSocket); - - socket.connect(this.remoteServer, this.remotePort); - - this.readBuffer = new ByteArray(); - this.socket = socket; - } - - private function didConnectSocket(event:Event):void { - this.externalInvoke('connected'); - } - - private function didCloseSocket(event:Event):void { - this.externalInvoke('close'); - } - - private function didIOErrorSocket(event:IOErrorEvent):void { - this.externalInvoke('error', event.text); - } - - private function didSecurityErrorSocket(event:SecurityErrorEvent):void { - this.externalInvoke('error', event.text); - } - - private function didReceiveSocket(event:Event):void { - var b:ByteArray = this.readBuffer; - this.socket.readBytes(b, b.length); - - do { - b = this.readBuffer; - b.position = 0; - - if (b.length <= 8) { - break; - } - - var msg_len:Number = parseInt(b.readUTFBytes(8), 10); - if (b.length >= msg_len + 8) { - var bytes:String = b.readUTFBytes(msg_len); - var data:Object = vegas.strings.JSON.deserialize(bytes); - var t:ByteArray = new ByteArray(); - t.writeBytes(b, msg_len + 8); - this.readBuffer = t; - - this.receiveMessage(data); - } else { - break; - } - } while (true); - - } - - public function receiveMessage(msg:Object):void { - this.externalInvoke('receive', msg); - } - - public function externalInvoke(type:String, object:Object = null):void { + protected function externalInvoke(type:String, object:Object = null):void { ExternalInterface.call('JX.Aphlict.didReceiveEvent', type, object); } - public function log(message:String):void { - ExternalInterface.call('console.log', message); + protected function log(message:String):void { + this.externalInvoke('log', message); } } diff --git a/support/aphlict/client/src/AphlictClient.as b/support/aphlict/client/src/AphlictClient.as new file mode 100644 index 0000000000..31105c67d1 --- /dev/null +++ b/support/aphlict/client/src/AphlictClient.as @@ -0,0 +1,129 @@ +package { + + import flash.events.TimerEvent; + import flash.external.ExternalInterface; + import flash.utils.Timer; + + + public class AphlictClient extends Aphlict { + + /** + * The connection name for this client. This will be used for the + * @{class:LocalConnection} object. + */ + private var client:String; + + /** + * The expiry timestamp for the @{class:AphlictMaster}. If this time is + * elapsed then the master will be assumed to be dead and another + * @{class:AphlictClient} will create a master. + */ + private var expiry:Number = 0; + + /** + * The interval at which to ping the @{class:AphlictMaster}. + */ + public static const INTERVAL:Number = 3000; + + private var master:AphlictMaster; + private var timer:Timer; + + private var remoteServer:String; + private var remotePort:Number; + + + public function AphlictClient() { + super(); + + ExternalInterface.addCallback('connect', this.externalConnect); + ExternalInterface.call( + 'JX.Stratcom.invoke', + 'aphlict-component-ready', + null, + {}); + } + + public function externalConnect(server:String, port:Number):void { + this.externalInvoke('connect'); + + this.remoteServer = server; + this.remotePort = port; + + this.client = AphlictClient.generateClientId(); + this.recv.connect(this.client); + + this.timer = new Timer(AphlictClient.INTERVAL); + this.timer.addEventListener(TimerEvent.TIMER, this.keepalive); + + this.connectToMaster(); + } + + /** + * Generate a unique identifier that will be used to communicate with the + * @{class:AphlictMaster}. + */ + private static function generateClientId():String { + return 'aphlict_client_' + Math.round(Math.random() * 100000); + } + + /** + * Create a new connection to the @{class:AphlictMaster}. + * + * If there is no current @{class:AphlictMaster} instance, then a new master + * will be created. + */ + private function connectToMaster():void { + this.timer.stop(); + + // Try to become the master. + try { + this.log('Attempting to become the master...'); + this.master = new AphlictMaster(this.remoteServer, this.remotePort); + this.log('I am the master.'); + } catch (x:Error) { + // Couldn't become the master + this.log('Cannot become the master... probably one already exists'); + } + + this.send.send('aphlict_master', 'register', this.client); + this.expiry = new Date().getTime() + (5 * AphlictClient.INTERVAL); + this.log('Registered client ' + this.client); + + this.timer.start(); + } + + /** + * Send a keepalive signal to the @{class:AphlictMaster}. + * + * If the connection to the master has expired (because the master has not + * sent a heartbeat signal), then a new connection to master will be + * created. + */ + private function keepalive(event:TimerEvent):void { + if (new Date().getTime() > this.expiry) { + this.connectToMaster(); + } + + this.send.send('aphlict_master', 'ping', this.client); + } + + /** + * This function is used to receive the heartbeat signal from the + * @{class:AphlictMaster}. + */ + public function pong():void { + this.expiry = new Date().getTime() + (2 * AphlictClient.INTERVAL); + } + + /** + * Receive a message from the Aphlict Server, via the + * @{class:AphlictMaster}. + */ + public function receiveMessage(msg:Object):void { + this.log('Received message.'); + this.externalInvoke('receive', msg); + } + + } + +} diff --git a/support/aphlict/client/src/AphlictMaster.as b/support/aphlict/client/src/AphlictMaster.as new file mode 100644 index 0000000000..1991ab48bd --- /dev/null +++ b/support/aphlict/client/src/AphlictMaster.as @@ -0,0 +1,166 @@ +package { + + import flash.events.Event; + import flash.events.IOErrorEvent; + import flash.events.ProgressEvent; + import flash.events.SecurityErrorEvent; + import flash.events.TimerEvent; + import flash.net.Socket; + import flash.utils.ByteArray; + import flash.utils.Dictionary; + import flash.utils.Timer; + import vegas.strings.JSON; + + + public class AphlictMaster extends Aphlict { + + /** + * The pool of connected clients. + */ + private var clients:Dictionary; + + /** + * A timer used to trigger periodic events. + */ + private var timer:Timer; + + /** + * The interval after which clients will be considered dead and removed + * from the pool. + */ + public static const PURGE_INTERVAL:Number = 3 * AphlictClient.INTERVAL; + + /** + * The hostname for the Aphlict Server. + */ + private var remoteServer:String; + + /** + * The port number for the Aphlict Server. + */ + private var remotePort:Number; + + private var socket:Socket; + private var readBuffer:ByteArray; + + + public function AphlictMaster(server:String, port:Number) { + super(); + + this.remoteServer = server; + this.remotePort = port; + + // Connect to the Aphlict Server. + this.recv.connect('aphlict_master'); + this.connectToServer(); + + this.clients = new Dictionary(); + + // Start a timer and regularly purge dead clients. + this.timer = new Timer(AphlictMaster.PURGE_INTERVAL); + this.timer.addEventListener(TimerEvent.TIMER, this.purgeClients); + this.timer.start(); + } + + /** + * Register a @{class:AphlictClient}. + */ + public function register(client:String):void { + if (!this.clients[client]) { + this.log('Registering client: ' + client); + this.clients[client] = new Date().getTime(); + } + } + + /** + * Purge stale client connections from the client pool. + */ + private function purgeClients(event:TimerEvent):void { + for (var client:String in this.clients) { + var checkin:Number = this.clients[client]; + + if (new Date().getTime() - checkin > AphlictMaster.PURGE_INTERVAL) { + this.log('Purging client: ' + client); + delete this.clients[client]; + } + } + } + + /** + * Clients will regularly "ping" the master to let us know that they are + * still alive. We will "pong" them back to let the client know that the + * master is still alive. + */ + public function ping(client:String):void { + this.clients[client] = new Date().getTime(); + this.send.send(client, 'pong'); + } + + private function connectToServer():void { + var socket:Socket = new Socket(); + + socket.addEventListener(Event.CONNECT, didConnectSocket); + socket.addEventListener(Event.CLOSE, didCloseSocket); + socket.addEventListener(ProgressEvent.SOCKET_DATA, didReceiveSocket); + + socket.addEventListener(IOErrorEvent.IO_ERROR, didIOErrorSocket); + socket.addEventListener( + SecurityErrorEvent.SECURITY_ERROR, + didSecurityErrorSocket); + + socket.connect(this.remoteServer, this.remotePort); + + this.readBuffer = new ByteArray(); + this.socket = socket; + } + + private function didConnectSocket(event:Event):void { + this.externalInvoke('connected'); + } + + private function didCloseSocket(event:Event):void { + this.externalInvoke('close'); + } + + private function didIOErrorSocket(event:IOErrorEvent):void { + this.externalInvoke('error', event.text); + } + + private function didSecurityErrorSocket(event:SecurityErrorEvent):void { + this.externalInvoke('error', event.text); + } + + private function didReceiveSocket(event:Event):void { + var b:ByteArray = this.readBuffer; + this.socket.readBytes(b, b.length); + + do { + b = this.readBuffer; + b.position = 0; + + if (b.length <= 8) { + break; + } + + var msg_len:Number = parseInt(b.readUTFBytes(8), 10); + if (b.length >= msg_len + 8) { + var bytes:String = b.readUTFBytes(msg_len); + var data:Object = vegas.strings.JSON.deserialize(bytes); + var t:ByteArray = new ByteArray(); + t.writeBytes(b, msg_len + 8); + this.readBuffer = t; + + // Send the message to all clients. + for (var client:String in this.clients) { + this.log('Sending message to client: ' + client); + this.send.send(client, 'receiveMessage', data); + } + } else { + break; + } + } while (true); + } + + } + +} diff --git a/webroot/rsrc/swf/aphlict.swf b/webroot/rsrc/swf/aphlict.swf index 4ac315b9de8a6669fe373cfbd9e5449814371dc2..bccd0f0d47070f7c0e31d73d8bc76a773f209dcf 100644 GIT binary patch literal 9213 zcmV5numI(~Q8%RP}2PU*+Yyat$l2l8i{_+)) zB)zlZWgC;y zX5?tjo=D~N0iy1jj zE}0ukZ0()U%z{9M2^(DSd1ph1k&JiBd~Y!lu{lzNw{9>Tq&+FcD8ArxH7+P+0{EjA3|* z`uis`=^O+mhPw-_1F5O>(S$OUP7XVUa+zdm#Ia8l%ElAfEP7QQOOKQ;&s}w~IAp3h za%3cZB$qxioG_B9B(Lw0(ZtwLqx+C`d$ zyISR7xYMbUYPFVB)9RAyRn==KQ7RZ!nCxH*W3rQ}#Y`zBGZ)n6EKCe$<0GjR}dVkRESIidkA?>)8y_ zL^_3O(Tvr4_=K3_^~+UU_T|VXGE<3+!k4TI=5k@hE6yawu{I2ejBe{=KeB5V)zNAs zv4E)ulH-X?ku^^zbIGx+n&T9=po{6eY!a&n2KMY2bRA73CiF2(T@CdWxvooQbG$9f z?1njz-lKz(X;@Yb{{_uuty+60$76|1`30Pf0VSJDPps|Dgh-5;AwjzRItWou=(wN^GR zCtiB-TfIEfMQdjL^7LgwR$6HZvG{ghuriAst5mmVjn!JtOk#xhVn*r5j9?>)93KRZ z#PNw_=7eX^PD~7Yt?}bkvpGGJTfeMH7ADpOov8{nlnM0W>Ps^$3@OhA>FLynJf0mX zxA(+huf46cFzmp5mt47=!KUu9Ha~kWyzJK2-qEE5+dIQ@IM6A#wY6e@3&%eTGd+vc0z1nvFx@_S(? zcIIF>T!Fn%t}d>v;X9!ku92OswWN;J)zr1swbymjb=GxNACXH4-{IUv#U-U>S~;O1 zMk%8XMj4|{M%_#CB}{E#WHobm8C}cBIz}5A zSKmX~lL*R#fho?vqwTB(h@T?rFZ)NoCiOJ$n)M zA?!!E9$^q+2;l(2L4+F+ZbY~V;TD8Lak6I^ae|a=ak(X0RMsP5bEZu_Qk{%VdsUCr zfPK57NAgHSEfR^2VkAlc4SZX7*7iyYaaH$9DsgY>l^mpKbFaimF*g1PsiQKHO0Sm* z{+y(QZ~i5vfEL*C%lMW|rMkmp{a0#632Fd%;Bq&-qL{t;fKN5IN2x)1h{#eic_N~a znO)#VF-0L{S_iby$k9Sm)L}S$C3%BIoY>blh)>N|Zf^FPTMkMQm$J$9@dlD*cTp0Y zEfyGPIZvuci|Nn%N+NEu$qeRa^&&HrpVN!Y);!s!bM4jv^4y${HtueeBI~6_)zb2b8NJE8CGYD&mKh=P5HEcL zN{{X&wcS0dy^^X>cTqdEGoU7|n^`IwAS)*#<)yp)~NZRYKH-!7rj+w;Bw3zOY}j80%O*EV1>1(?hi-DqqK zM4OG~K(xhZ2}J#dKM)NVfj~591Ow46#uo7?0JDbC67X5b><7imkeRhD+NUIra3$%1 z7kb{geAg`9e{gW;jw1^Qt&nPgqXp#lX8>-NI@mv#;+oe3FaoF)P|gK=)&dS&*l%q7 z(~rX<&M$iA#8Pm>tgS0+!Jan*b&6p-7_s4D_9C=nZGi>gX4R^2{4D`VMF~a`#z)-pZ)< zUAJ#&M=2+drLzf(Sh7Ep9?1Y!2;QQheSO#NIB=xD_dqY_x8aGEwRm8kK$;?_b70?* z9fO1W26;9+!OG?tO2j8|a6Yk^xm4IJ1`gb8u~dU)Stg6owf#gc(VNNWCjj*I;q8-# zk;oK~SfTp%5$A%L;j+II!xx+*3MZrs*m)Z)YnnK3k;Y5+3(vgRU}}P+Z6ycL|N6q0 zHHhzZ#a^NjY-mSfj}F`{Q%vcim#ErLZZkxAm9b6diFj2k!vTm2BMJ$#VbK$IU# z3S<8QMELsEUN&4Vi%vU&LAe!Rw5_d6?raUnU9Ca6tD{2+1_GUnkUiKQ4g;ccbPCm! z5Rj-6Y7cY>oT`MwtzAH;t({7^tsRe!K;ZuwPKDxaA()cdDmhTCEv_!Fu2xqArg{ZT zEv{Qrx3+FwU1Qz)>bB}b)yFwhbu404LbnU3sxYcD;$ox#RS66{8Y9BM!*OaQQ>y?g zIdY{yu62w8vo_QdCJTV-+{EY>CIgxVSa~Z`+ZpX(q?6GuM!K1L6{A-(at%|rGP;eC z9;O1UZfB&ADgBJ>U?j}sU5xHwbU&kmj1Dn+kkK0$y^(oqqcDsIQ-EW@5uQCUCDoMc7C=IK>rMX7(Q9;e3i>3 zkurA=3}1wl^hiYj!7yS~NJLh9q)LF(<{oJ!FtD#j+9DB07q@INO+eso0fC(Y0bRIMwx?NLw>>n z#T>OBeZ>KsiVRHhp9hfkn*ok|L;2ZJ#SG`?Mpd&t&p~j636L6b0^oJ!qpsa9Y1D0A zosSkpi;ZHS)*>=mVqTLsN}{DksZj=K8z~2B-3m&?1Ey_2V3b3(b`;sqi(Do3n>+G` zd)BCW$Wsq67|HvZW@jSRC}}6BM{9Q1NC3Thl{o-zS$4RKrog>7AMlyTaU_s>R$1Sx>VS6-(^1hZi ztK0)T>#bFr%zYtMDgW~Pyi;{5=8Y&_;ks`|>4z=d51U6W(DAK#qi)t0jMSsrIyh9$ z@m>O!IA;k|50Mi?}BTRysF_ZCU_0YA^`&1M!F zIVd!$fkKm9A)hp9PUU?&BQ0p~V@Sr_w~|j-$tM7*eY-{S?MQa=`qY8@4lDT%^BsBL zb+d*)(t`5di5xDTV-<4TNvte)67wWklIbpf8gnadchL(J*-jzb#&h0Nam70wh^yY| zEpZ3F7}xC-IZv)9?UIb0o&BaraT^Ul(J(x5m^+Jq}!tl90<;p2zre zIh`7>#3zX6MD#dmDp%*{%_n$E78Oo34znzJwRL*A#<(UB-D+$NM7J5+0?{6$ClKv5 zdIQm`jH|?B@kCRME+~eW=PC(WliQlb7VWpUXg}Yz3(g<+t~W3#7p#w2zbypLo@L^$ z;^J^Dxda#}e<3IO!VY6~# z;l*OxgH3@u5Riv@a0(>mtx*!CyQu^>z7K|Wa=8-&sbLti{jeFz$y83A(#IwfSI(Y=Ta6zI+Ak{Rbqn4P zhZnaE^P<^yc=-}~>Q7-u(SbKpYEo1b{zH^!pY5)U4+Y^+GMR}dF0RwX6z)7Oj5&C~ zd6!?lI~H=Uyg2t_KbBvVSiH0!FFTN72L-eYbaa(kEQKCWLZM(t355f#&O##rhPEPa zTc~p>lm;$s?{qCFs)RZ^+Z>ic?nM=qU}s0CQcawm>a~=}#f)ISFoF1r8HIZfu&$ob zRg8L>yw0_b6p7^lo;J)X$FwTRPQ1x(yeR_CluWDe%#}@-5=GKLmCCW05Xn_Zs;Uuc z5LO`6A*@7bKv<2i2B8sdHdS&t)$M>VlG?}Tr(-*i3w89t{wK5Tu>UEn5B5J5K!_2C zi-R95iNsCZu=^1wY%T;QMNDBgpWGTIH#N6Ji@Y~+jKbY<&sF~KIquc>w7fBEA?uQf zW-TjM!dqBSN{%cY-k~=xeQEZ>s&=JpD7?%rw=hRq-)zYRhNa8el`}7{HB`?LFO82j zzp(;KRvZ#1Nis&VWJ=DZ4OJK%?8A1|@!W4qSkQb2ss|pFS))61oGrc)-h#rd3Lk2yR zqK7i{5bjT;hZAm|*oT+ioN{O~5D*Sx)fh{|8|Wm(n5HGfWnb2Cq=Y}xVL=QQvo@72 zZ`^VVOB&IY6tISRY!sR)6O-A|BGFuyS-~08hecCb_L1Nl3tqhRp>vxL8Fz7U!f13w z+`=A10;DT^C1obF{mGGJj@dEk#VO8czcLBC632xQ^!0eMFFlq{x!*PkZ}k9r_;^uv z@tyH`e|(=oHaO5s*CtL_P_1B+5kTvL1#Zcmn4^gkZ(>ziY);-wBqfg~jw{*ZNQyL* zzqN1$npo$Tw z97|`0uW0BAL`eK(bHyaT0yUmY!N&~C;yAyIS7hDoyYc}oCKyRvQJ-_wm*5N=d0ZCq zw1$G6i=d`8+}5GAwgp?4VJ4*&hB~FSvm<;VE@}&Ob}4P4_T?a`tpo4|2D-4y?O_2t z+uK5Tc67C?!C*&6mm1`E2=ENGf*wM7DsDOj@!lF}>r{hnogw6bC9hLO#!wi~jv$_) zPDl%dJHmJmcZS;(FaGe_74Ev=3}YKmFY8rSS|JsOmr$!4<~mwSRB!c~nl;X~b)@=z zL~#OQDJsl!#6{F@MpWTIb~6I+aS4M-j+S${Y%7uMO=SLWL#3>P)b3BqZsZ? zO*{Bmbe|R7Z$%GU(L+}Bh!uUriXOG1$E@h1 zR`f9|`nVN+!ir|B=y5B0!it`>qNl9rlUDR8EBdq*ea4DDYei3!XSmj%v%Wr0NJpnj zCLvPi>=8%S@OF-g!+jhRw{GW{xV4XC;;eyzg)%lWNkzJ@9q)H30FlVqd?*VO%Z6eYO-F zxM^-yd>f!Rs-md;mfP*1-jO#5T<LZ~`DIvcs&KOS8GH2Vaae=?!TNZQQIdsq>Lu8kvgfogw~XbX@@bN!-da*5_5>xm&obov*%97l&Wvf&->P!KSI)suW4qN_7sXZ zOJ)u2LEpxThq;Mt6ZIyswVw&qaKJQwfj3*bU*a_%b0Ujx%M8>Mdj6P%irnS* z!X{Sabo+efzX&~>XLk8o%$Lb7m-#ABj?)njId#_jEt&IGl?9>L@9-9S8Z{|*peA#^z|&K_2=hO= z!XcsCAMiTI-?SzoX^-Th40ch1k(&(F8a&-c#HgJk}i zoNgpD*2sJ3YcOf@8U$w0SD(V|9NvAqT=AnCsVP{%e6i zgns?zzZD2n=(odss-T~|sGlPAQ=s2t^YhA+f1Ll$tMmW;)%g$2&*Ph$60i<@jbKjy z9p%RCozmB-`E`1OG+lhge2&7R>sw#>Ug-4#%|~kB;P?h&enIC&k=9g+hA_Wnr+u5w z?&7WMGXI{=@Vv$xw`@Di&V^O zyB7Ig7WrzWm#J^i{8u{r44=S!*w6Zgo|%Hg5}tD>a+-EdlbXM#`Ps-S!e@vFS$#Jw zWxJ7!u;@FN(r*&tN@Z11-%TO!KZLw`>Gu@Yck%~3-$MV0=OOu3YW|*A^VAvh4~U(< zEzmx)nr6?Me-z&V`}>^vs`x%^e`8I2jh>!csKe>T`Ok4>D)@q=Sah^4-g$y2fcBl1 z^AWFvlJ3L{@6MAl@9Hg;Flw3alF=!5%T_b5;mxeUTZl=#B+mzVo(~H`RSAHP<_6=# zG8)`H1F`o&Y>hNk{#|s~qe~^3kIC45%4F=0o6s7MV-Gc-l=G-AuZ)Lazj=y(qT6P$ z2Yr&4fbP(E`+Y-+LwErS#hFBAwXh7aXBUlxq z$n!NTkA_Bena|6oMa9pVFW9VK=aq0r){^p{qX}M=Py1*k295bGyD`>@X4OFXo*ZqA zDZZmKr)MIKWS53*#C%Df^$pIPJYz{eZ8a-&{*f(x){?%;l73dGIaawHoIeKV80W;w z?K1yyf%7MV^CTbUe4pYq8T`EXEL05RzWn>p^=EP;nSJ8qS@Y*|w0sWx%tIco_ru~MEu6C&%Yz)qwu#PtywH8zq8Z+1I1`>=e7AGC>yw>SMBVtiR@d%!ZEFAF-SbA zSj*I1%A8n%^iuO(AaUWRxaZVo34f2B?QR8ic%MkH)}Qw)V*R<-PXD0I`+Hu}RQUTJ2 z@I0n`T)_Z+R1w4VF$Hb&384u#Ud-M?zZ}MZ`#Aw9Ij%mgn2+-u5UV}UciN};SIi;W z>r=MMpXOEitPm8c{1CQjlegXHlsVruGbrNoigt{%J`2KDPWY0d8JzI9AZ+7=uPWL> zPWUqT;bisM`FY2E zugyRC+WfPx&425)`LnOh|LV1QP{k_w&jn4*Cxn($<*k4Pzp{swb))rVg>P#W_!W}+ zD4$dRhH+(@_F#NPbgr)wBgFg-Xg+C|`CCC-FKE95tr@ic6ts&+6X*K_@_3QwRgotl z_~t=t0qrgoEs5oUFBXMSh}D5F96ZBG4YNNV@k=M6VkO@vf51?-TTsq!K4#?QhX(mUsIRkwvUU*hIwAwC(AKmMv91fYjxuF(@8W zweRrW{)8>|0RMP`%boIcqqwI;5qFWwHTd|H$mBzTW%&Ax#bSO|)z)D{;f?T&ErpM= zzgDej9pKZtsr=I@?8~Zl3zz>@J1HoZKFoLX0l|0%qRofYS$lMGjEEE6$7}*w92r!M z4C*BH&(6=&()szF^YeHU4)5nxzEqp<7j-Cq9wXsJe*LzJcl{~euHQwwntw0qHCee0 zS$|+v>+O7%uoiPnH{X=_6b;Bf-$Sr$aBTLHUF{#LO}n%i5axuan=1F>{YRFloy$el zE&r^49m!{H$>-D!yR-E3xBntuBy^Pod+_Y)L;?y}Qg`E^Te| zpFxtOY8Ms{!!1eMFd*7rgrmzAs@KTyT4> zTlqTHXDi#_pU>eX1j4yd_$?*;D7N>OCWn=jKAu=K#W!6}Dd7qe(rmA>G6}~ucb4-X zx5(?(d1WuI&U)9aQ{ zEOHOHab2F@MZ+-;W*_cqg*}o}71cKI$g1k-!Y~VPT%$;Ms00rO#RJ#>_%*VaGC6m6^Mu#2_<1Z6?YLHsdSjpm`t) z5KJRZATGXiUOVfnz&DPvXUsi$L-tniWo+N9uM!_KzABM${Vb-3%&kpp#Prw_E#^NQ z2tPtRA9bk*(Vm-1kUI;+&%JPW7Bdg?45n_&29J3rZ1DUST(H4cF?kJs zrsZ10e~OHMTA>MF)?cJw%0r3Bu99tNC19L^r6%Y$E9LrLp81a7}#!oP)2DJlgp z^%NbZMU}K2rap&`6E%J)c3Ac~bsR%n^0vc@&#eP>7b*RRRbR2Lo+l;hz+s24R0l>c zbL>6Le436sdF5>Au+!(!otU}MPf^|ZKz=}arNX>{&*j2SRDr7(#Y<-yCRv5pi98j2 T7qYLRTR(h}dO-O<`+!RI$|eAh literal 7217 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 Date: Thu, 29 May 2014 08:33:25 -0700 Subject: [PATCH 16/21] Point github.com/facebook URIs at github.com/phacility insead Summary: Point everything at the new canonical URI. Test Plan: `grep` Reviewers: chad Reviewed By: chad Subscribers: epriestley Differential Revision: https://secure.phabricator.com/D9328 --- resources/sql/patches/20131004.dxreviewers.php | 2 +- scripts/install/install_rhel-derivs.sh | 6 +++--- scripts/install/install_ubuntu.sh | 6 +++--- .../repository/engine/PhabricatorRepositoryPullEngine.php | 2 +- src/docs/user/feedback.diviner | 2 +- src/docs/user/installation_guide.diviner | 6 +++--- src/docs/user/userguide/arcanist.diviner | 4 ++-- src/docs/user/userguide/arcanist_quick_start.diviner | 4 ++-- 8 files changed, 16 insertions(+), 16 deletions(-) diff --git a/resources/sql/patches/20131004.dxreviewers.php b/resources/sql/patches/20131004.dxreviewers.php index 3904613eb3..8ff3bc32f8 100644 --- a/resources/sql/patches/20131004.dxreviewers.php +++ b/resources/sql/patches/20131004.dxreviewers.php @@ -32,7 +32,7 @@ foreach (new LiskMigrationIterator($table) as $revision) { if (phid_get_type($dst) == PhabricatorPHIDConstants::PHID_TYPE_UNKNOWN) { // At least one old install ran into some issues here. Skip the row if we // can't figure out what the destination PHID is. See here: - // https://github.com/facebook/phabricator/pull/507 + // https://github.com/phacility/phabricator/pull/507 continue; } diff --git a/scripts/install/install_rhel-derivs.sh b/scripts/install/install_rhel-derivs.sh index a09949f29b..58753c038c 100755 --- a/scripts/install/install_rhel-derivs.sh +++ b/scripts/install/install_rhel-derivs.sh @@ -119,21 +119,21 @@ confirm if [[ ! -e libphutil ]] then - git clone git://github.com/facebook/libphutil.git + git clone git://github.com/phacility/libphutil.git else (cd libphutil && git pull --rebase) fi if [[ ! -e arcanist ]] then - git clone git://github.com/facebook/arcanist.git + git clone git://github.com/phacility/arcanist.git else (cd arcanist && git pull --rebase) fi if [[ ! -e phabricator ]] then - git clone git://github.com/facebook/phabricator.git + git clone git://github.com/phacility/phabricator.git else (cd phabricator && git pull --rebase) fi diff --git a/scripts/install/install_ubuntu.sh b/scripts/install/install_ubuntu.sh index e736b7128f..265d044883 100755 --- a/scripts/install/install_ubuntu.sh +++ b/scripts/install/install_ubuntu.sh @@ -64,21 +64,21 @@ fi if [ ! -e libphutil ] then - git clone git://github.com/facebook/libphutil.git + git clone git://github.com/phacility/libphutil.git else (cd libphutil && git pull --rebase) fi if [ ! -e arcanist ] then - git clone git://github.com/facebook/arcanist.git + git clone git://github.com/phacility/arcanist.git else (cd arcanist && git pull --rebase) fi if [ ! -e phabricator ] then - git clone git://github.com/facebook/phabricator.git + git clone git://github.com/phacility/phabricator.git else (cd phabricator && git pull --rebase) fi diff --git a/src/applications/repository/engine/PhabricatorRepositoryPullEngine.php b/src/applications/repository/engine/PhabricatorRepositoryPullEngine.php index e935740743..5ce19f875f 100644 --- a/src/applications/repository/engine/PhabricatorRepositoryPullEngine.php +++ b/src/applications/repository/engine/PhabricatorRepositoryPullEngine.php @@ -384,7 +384,7 @@ final class PhabricatorRepositoryPullEngine // This behavior has been reverted, but users who updated between Feb 1, // 2012 and Mar 1, 2012 will have the erroring version. Do a dumb test // against stdout to check for this possibility. - // See: https://github.com/facebook/phabricator/issues/101/ + // See: https://github.com/phacility/phabricator/issues/101/ // NOTE: Mercurial has translated versions, which translate this error // string. In a translated version, the string will be something else, diff --git a/src/docs/user/feedback.diviner b/src/docs/user/feedback.diviner index 216482030d..bfb395be2b 100644 --- a/src/docs/user/feedback.diviner +++ b/src/docs/user/feedback.diviner @@ -39,7 +39,7 @@ requests, general questions, or random feedback this way, too. = GitHub Issues = You can also use -[[https://github.com/facebook/phabricator/issues/new | GitHub Issues]] if you +[[https://github.com/phacility/phabricator/issues/new | GitHub Issues]] if you prefer. = IRC = diff --git a/src/docs/user/installation_guide.diviner b/src/docs/user/installation_guide.diviner index ece216513b..b829c5aa1f 100644 --- a/src/docs/user/installation_guide.diviner +++ b/src/docs/user/installation_guide.diviner @@ -95,9 +95,9 @@ Now that you have all that stuff installed, grab Phabricator and its dependencies: $ cd somewhere/ # pick some install directory - somewhere/ $ git clone git://github.com/facebook/libphutil.git - somewhere/ $ git clone git://github.com/facebook/arcanist.git - somewhere/ $ git clone git://github.com/facebook/phabricator.git + somewhere/ $ git clone git://github.com/phacility/libphutil.git + somewhere/ $ git clone git://github.com/phacility/arcanist.git + somewhere/ $ git clone git://github.com/phacility/phabricator.git = Installing APC (Optional) = diff --git a/src/docs/user/userguide/arcanist.diviner b/src/docs/user/userguide/arcanist.diviner index b9c497007c..5211e173d8 100644 --- a/src/docs/user/userguide/arcanist.diviner +++ b/src/docs/user/userguide/arcanist.diviner @@ -92,8 +92,8 @@ have PHP installed, you can download it from . To install Arcanist, pick an install directory and clone the code from GitHub: - some_install_path/ $ git clone git://github.com/facebook/libphutil.git - some_install_path/ $ git clone git://github.com/facebook/arcanist.git + some_install_path/ $ git clone git://github.com/phacility/libphutil.git + some_install_path/ $ git clone git://github.com/phacility/arcanist.git This should leave you with a directory structure like this diff --git a/src/docs/user/userguide/arcanist_quick_start.diviner b/src/docs/user/userguide/arcanist_quick_start.diviner index 141416d301..3d4407f42a 100644 --- a/src/docs/user/userguide/arcanist_quick_start.diviner +++ b/src/docs/user/userguide/arcanist_quick_start.diviner @@ -23,8 +23,8 @@ Then install Arcanist itself: $ mkdir somewhere/ $ cd somewhere/ - somewhere/ $ git clone git://github.com/facebook/libphutil.git - somewhere/ $ git clone git://github.com/facebook/arcanist.git + somewhere/ $ git clone git://github.com/phacility/libphutil.git + somewhere/ $ git clone git://github.com/phacility/arcanist.git Add `arc` to your path: From 3929309225c780d36a4a00a7ba014d0d4b07762f Mon Sep 17 00:00:00 2001 From: epriestley Date: Thu, 29 May 2014 12:01:30 -0700 Subject: [PATCH 17/21] Update config to point at modern custom field article. Summary: Fixes T5215. This mentions an old article name. Test Plan: Read config option. Reviewers: chad Reviewed By: chad Subscribers: epriestley Maniphest Tasks: T5215 Differential Revision: https://secure.phabricator.com/D9331 --- .../maniphest/config/PhabricatorManiphestConfigOptions.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/applications/maniphest/config/PhabricatorManiphestConfigOptions.php b/src/applications/maniphest/config/PhabricatorManiphestConfigOptions.php index aaaa4e79ff..6b03cae03c 100644 --- a/src/applications/maniphest/config/PhabricatorManiphestConfigOptions.php +++ b/src/applications/maniphest/config/PhabricatorManiphestConfigOptions.php @@ -218,9 +218,9 @@ EOTEXT ->setSummary(pht("Custom Maniphest fields.")) ->setDescription( pht( - "Array of custom fields for Maniphest tasks. For details on ". - "adding custom fields to Maniphest, see 'Maniphest User Guide: ". - "Adding Custom Fields'.")) + 'Array of custom fields for Maniphest tasks. For details on '. + 'adding custom fields to Maniphest, see "Configuring Custom '. + 'Fields" in the documentation.')) ->addExample( '{"mycompany:estimated-hours": {"name": "Estimated Hours", '. '"type": "int", "caption": "Estimated number of hours this will '. From 2f668493a0fb330ca68181ca0479ac73f34d0ae7 Mon Sep 17 00:00:00 2001 From: Joshua Spence Date: Thu, 29 May 2014 12:02:37 -0700 Subject: [PATCH 18/21] Don't attempt to discover parents commits for untracked branchs. Summary: Fixes T5195. Currently, the `./bin/repository parents` workflow doesn't respect tracked branches and will attempt to build parents caches for all branches. Test Plan: For at least one of our repositories, this patch fixes the `Unknown commit` exception. Unfortunately, it doesn't seem to completely solve this problem though, but I suspect that this is due to commits that were overwritten with a `git push --force` or similar. Reviewers: #blessed_reviewers, epriestley Reviewed By: #blessed_reviewers, epriestley Subscribers: epriestley, Korvin Maniphest Tasks: T5195 Differential Revision: https://secure.phabricator.com/D9322 --- .../PhabricatorRepositoryManagementParentsWorkflow.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/applications/repository/management/PhabricatorRepositoryManagementParentsWorkflow.php b/src/applications/repository/management/PhabricatorRepositoryManagementParentsWorkflow.php index fd49df59a0..86fb07c7bf 100644 --- a/src/applications/repository/management/PhabricatorRepositoryManagementParentsWorkflow.php +++ b/src/applications/repository/management/PhabricatorRepositoryManagementParentsWorkflow.php @@ -58,6 +58,10 @@ final class PhabricatorRepositoryManagementParentsWorkflow $graph = array(); foreach ($refs as $ref) { + if (!$repo->shouldTrackBranch($ref->getRefName())) { + continue; + } + $console->writeOut( "%s\n", pht('Rebuilding branch "%s"...', $ref->getRefName())); From 81d95cf682a5375c6c5116f0387ad1e26f91aa9f Mon Sep 17 00:00:00 2001 From: epriestley Date: Thu, 29 May 2014 12:17:54 -0700 Subject: [PATCH 19/21] Make default view of "Applications" app a full-page launcher Summary: This probably needs some tweaks, but the idea is to make it easier to browse and access applications without necessarily needing them to be on the homepage. Open to feedback. Test Plan: (This screenshot merges "Organization", "Communication" and "Core" into a single "Core" group. We can't actually do this yet because it wrecks the homepage.) {F160052} Reviewers: btrahan, chad Reviewed By: chad Subscribers: epriestley Maniphest Tasks: T5176 Differential Revision: https://secure.phabricator.com/D9297 --- .../PhabricatorApplicationAudit.php | 8 +- .../PhabricatorApplicationAuth.php | 4 + .../base/PhabricatorApplication.php | 8 +- .../PhabricatorApplicationCalendar.php | 2 +- .../PhabricatorApplicationChatLog.php | 2 +- .../PhabricatorApplicationConduit.php | 2 +- .../PhabricatorApplicationConfig.php | 4 + .../PhabricatorApplicationConpherence.php | 2 +- .../PhabricatorApplicationCountdown.php | 2 +- .../PhabricatorApplicationDaemons.php | 2 +- .../PhabricatorApplicationDashboard.php | 2 +- .../PhabricatorApplicationDifferential.php | 8 ++ .../PhabricatorApplicationDiffusion.php | 2 +- .../PhabricatorApplicationDiviner.php | 2 +- .../PhabricatorApplicationDoorkeeper.php | 8 +- .../PhabricatorApplicationDrydock.php | 4 + .../PhabricatorApplicationFact.php | 2 +- .../PhabricatorApplicationFeed.php | 2 +- .../PhabricatorApplicationFlags.php | 4 +- .../PhabricatorApplicationHarbormaster.php | 2 +- .../PhabricatorApplicationLegalpad.php | 2 +- .../PhabricatorApplicationApplications.php | 5 +- ...ricatorApplicationDetailViewController.php | 39 +++++- .../PhabricatorApplicationEditController.php | 6 +- ...bricatorApplicationUninstallController.php | 4 + .../PhabricatorApplicationsController.php | 4 - .../PhabricatorApplicationsListController.php | 4 + .../meta/query/PhabricatorAppSearchEngine.php | 126 +++++++++++++++--- .../query/PhabricatorApplicationQuery.php | 15 +++ .../PhabricatorApplicationMetaMTA.php | 8 +- .../PhabricatorApplicationNotifications.php | 2 +- .../PhabricatorApplicationNuance.php | 4 + .../PhabricatorApplicationOAuthServer.php | 8 +- .../PhabricatorApplicationOwners.php | 4 +- .../PhabricatorApplicationPassphrase.php | 2 +- .../PhabricatorApplicationPaste.php | 4 + .../PhabricatorApplicationPeople.php | 2 +- .../PhabricatorApplicationPhlux.php | 2 +- .../PhabricatorApplicationPholio.php | 2 +- .../PhabricatorApplicationPhortune.php | 2 +- .../PhabricatorApplicationPhrequent.php | 4 +- .../PhabricatorApplicationPonder.php | 2 +- .../PhabricatorApplicationProject.php | 2 +- .../PhabricatorApplicationReleeph.php | 2 +- .../PhabricatorApplicationRepositories.php | 2 +- .../PhabricatorApplicationSearch.php | 2 +- .../PhabricatorApplicationSettings.php | 6 +- .../PhabricatorApplicationTokens.php | 2 +- .../PhabricatorApplicationUIExamples.php | 2 +- src/view/phui/PHUIObjectItemView.php | 30 +++++ .../css/phui/phui-object-item-list-view.css | 51 +++++++ 51 files changed, 338 insertions(+), 84 deletions(-) diff --git a/src/applications/audit/application/PhabricatorApplicationAudit.php b/src/applications/audit/application/PhabricatorApplicationAudit.php index 87b6b2cfde..ef85b7c0fc 100644 --- a/src/applications/audit/application/PhabricatorApplicationAudit.php +++ b/src/applications/audit/application/PhabricatorApplicationAudit.php @@ -2,10 +2,6 @@ final class PhabricatorApplicationAudit extends PhabricatorApplication { - public function getShortDescription() { - return pht('Audit Code'); - } - public function getBaseURI() { return '/audit/'; } @@ -14,6 +10,10 @@ final class PhabricatorApplicationAudit extends PhabricatorApplication { return 'audit'; } + public function getShortDescription() { + return pht('Browse and Audit Commits'); + } + public function getHelpURI() { return PhabricatorEnv::getDoclink('Audit User Guide'); } diff --git a/src/applications/auth/application/PhabricatorApplicationAuth.php b/src/applications/auth/application/PhabricatorApplicationAuth.php index 0a25817907..3c51aa9bc0 100644 --- a/src/applications/auth/application/PhabricatorApplicationAuth.php +++ b/src/applications/auth/application/PhabricatorApplicationAuth.php @@ -14,6 +14,10 @@ final class PhabricatorApplicationAuth extends PhabricatorApplication { return 'authentication'; } + public function getShortDescription() { + return pht('Configure Login and Registration'); + } + public function getHelpURI() { // NOTE: Although reasonable help exists for this in "Configuring Accounts // and Registration", specifying a help URI here means we get the menu diff --git a/src/applications/base/PhabricatorApplication.php b/src/applications/base/PhabricatorApplication.php index bed89ed741..91acc55a8f 100644 --- a/src/applications/base/PhabricatorApplication.php +++ b/src/applications/base/PhabricatorApplication.php @@ -155,12 +155,10 @@ abstract class PhabricatorApplication } public function getHelpURI() { - // TODO: When these applications get created, link to their docs: - // - // - Drydock - // - OAuth Server - + return null; + } + public function getOverview() { return null; } diff --git a/src/applications/calendar/application/PhabricatorApplicationCalendar.php b/src/applications/calendar/application/PhabricatorApplicationCalendar.php index 9554557dc5..18c6b12d11 100644 --- a/src/applications/calendar/application/PhabricatorApplicationCalendar.php +++ b/src/applications/calendar/application/PhabricatorApplicationCalendar.php @@ -3,7 +3,7 @@ final class PhabricatorApplicationCalendar extends PhabricatorApplication { public function getShortDescription() { - return pht('Dates and Stuff'); + return pht('Upcoming Events'); } public function getFlavorText() { diff --git a/src/applications/chatlog/applications/PhabricatorApplicationChatLog.php b/src/applications/chatlog/applications/PhabricatorApplicationChatLog.php index 707cf46344..018cae36c0 100644 --- a/src/applications/chatlog/applications/PhabricatorApplicationChatLog.php +++ b/src/applications/chatlog/applications/PhabricatorApplicationChatLog.php @@ -7,7 +7,7 @@ final class PhabricatorApplicationChatLog extends PhabricatorApplication { } public function getShortDescription() { - return pht('Chat Log'); + return pht('IRC Logs'); } public function getIconName() { diff --git a/src/applications/conduit/application/PhabricatorApplicationConduit.php b/src/applications/conduit/application/PhabricatorApplicationConduit.php index 248877bb9b..e50778e30f 100644 --- a/src/applications/conduit/application/PhabricatorApplicationConduit.php +++ b/src/applications/conduit/application/PhabricatorApplicationConduit.php @@ -19,7 +19,7 @@ final class PhabricatorApplicationConduit extends PhabricatorApplication { } public function getShortDescription() { - return 'Conduit API Console'; + return pht('Phabricator Developer API Console'); } public function getTitleGlyph() { diff --git a/src/applications/config/application/PhabricatorApplicationConfig.php b/src/applications/config/application/PhabricatorApplicationConfig.php index d18b81c2df..aa3756c438 100644 --- a/src/applications/config/application/PhabricatorApplicationConfig.php +++ b/src/applications/config/application/PhabricatorApplicationConfig.php @@ -22,6 +22,10 @@ final class PhabricatorApplicationConfig extends PhabricatorApplication { return false; } + public function getShortDescription() { + return pht('Configure Phabricator'); + } + public function getRoutes() { return array( '/config/' => array( diff --git a/src/applications/conpherence/application/PhabricatorApplicationConpherence.php b/src/applications/conpherence/application/PhabricatorApplicationConpherence.php index 7a36283459..d86cb67722 100644 --- a/src/applications/conpherence/application/PhabricatorApplicationConpherence.php +++ b/src/applications/conpherence/application/PhabricatorApplicationConpherence.php @@ -10,7 +10,7 @@ final class PhabricatorApplicationConpherence extends PhabricatorApplication { } public function getShortDescription() { - return pht('Messaging'); + return pht('Send Messages'); } public function getIconName() { diff --git a/src/applications/countdown/application/PhabricatorApplicationCountdown.php b/src/applications/countdown/application/PhabricatorApplicationCountdown.php index ba01b55f57..e50dec7725 100644 --- a/src/applications/countdown/application/PhabricatorApplicationCountdown.php +++ b/src/applications/countdown/application/PhabricatorApplicationCountdown.php @@ -11,7 +11,7 @@ final class PhabricatorApplicationCountdown extends PhabricatorApplication { } public function getShortDescription() { - return pht('Countdown Timers'); + return pht('Countdown to Events'); } public function getTitleGlyph() { diff --git a/src/applications/daemon/application/PhabricatorApplicationDaemons.php b/src/applications/daemon/application/PhabricatorApplicationDaemons.php index f6582ccfee..4ceec3a4cb 100644 --- a/src/applications/daemon/application/PhabricatorApplicationDaemons.php +++ b/src/applications/daemon/application/PhabricatorApplicationDaemons.php @@ -7,7 +7,7 @@ final class PhabricatorApplicationDaemons extends PhabricatorApplication { } public function getShortDescription() { - return pht('Manage Daemons'); + return pht('Manage Phabricator Daemons'); } public function getBaseURI() { diff --git a/src/applications/dashboard/application/PhabricatorApplicationDashboard.php b/src/applications/dashboard/application/PhabricatorApplicationDashboard.php index 4c3f57b5ad..65704afd98 100644 --- a/src/applications/dashboard/application/PhabricatorApplicationDashboard.php +++ b/src/applications/dashboard/application/PhabricatorApplicationDashboard.php @@ -7,7 +7,7 @@ final class PhabricatorApplicationDashboard extends PhabricatorApplication { } public function getShortDescription() { - return pht('Such Data'); + return pht('Create Custom Pages'); } public function getIconName() { diff --git a/src/applications/differential/application/PhabricatorApplicationDifferential.php b/src/applications/differential/application/PhabricatorApplicationDifferential.php index 289a1a4d5e..b2816d6ab9 100644 --- a/src/applications/differential/application/PhabricatorApplicationDifferential.php +++ b/src/applications/differential/application/PhabricatorApplicationDifferential.php @@ -36,6 +36,14 @@ final class PhabricatorApplicationDifferential extends PhabricatorApplication { ); } + public function getOverview() { + return pht(<<[1-9]\d*)' => 'DifferentialRevisionViewController', diff --git a/src/applications/diffusion/application/PhabricatorApplicationDiffusion.php b/src/applications/diffusion/application/PhabricatorApplicationDiffusion.php index e22087af67..15865e5ceb 100644 --- a/src/applications/diffusion/application/PhabricatorApplicationDiffusion.php +++ b/src/applications/diffusion/application/PhabricatorApplicationDiffusion.php @@ -3,7 +3,7 @@ final class PhabricatorApplicationDiffusion extends PhabricatorApplication { public function getShortDescription() { - return pht('Repository Browser'); + return pht('Host and Browse Repositories'); } public function getBaseURI() { diff --git a/src/applications/diviner/application/PhabricatorApplicationDiviner.php b/src/applications/diviner/application/PhabricatorApplicationDiviner.php index 524786fe9d..da2fd4bcb8 100644 --- a/src/applications/diviner/application/PhabricatorApplicationDiviner.php +++ b/src/applications/diviner/application/PhabricatorApplicationDiviner.php @@ -36,7 +36,7 @@ final class PhabricatorApplicationDiviner extends PhabricatorApplication { } public function getApplicationGroup() { - return self::GROUP_COMMUNICATION; + return self::GROUP_UTILITIES; } public function getRemarkupRules() { diff --git a/src/applications/doorkeeper/application/PhabricatorApplicationDoorkeeper.php b/src/applications/doorkeeper/application/PhabricatorApplicationDoorkeeper.php index 24b605c1cc..d1e0281765 100644 --- a/src/applications/doorkeeper/application/PhabricatorApplicationDoorkeeper.php +++ b/src/applications/doorkeeper/application/PhabricatorApplicationDoorkeeper.php @@ -6,14 +6,14 @@ final class PhabricatorApplicationDoorkeeper extends PhabricatorApplication { return false; } - public function getBaseURI() { - return '/doorkeeper/'; - } - public function shouldAppearInLaunchView() { return false; } + public function getShortDescription() { + return pht('Connect to Other Software'); + } + public function getRemarkupRules() { return array( new DoorkeeperRemarkupRuleAsana(), diff --git a/src/applications/drydock/application/PhabricatorApplicationDrydock.php b/src/applications/drydock/application/PhabricatorApplicationDrydock.php index fc2e39c4b4..06bd4d264a 100644 --- a/src/applications/drydock/application/PhabricatorApplicationDrydock.php +++ b/src/applications/drydock/application/PhabricatorApplicationDrydock.php @@ -30,6 +30,10 @@ final class PhabricatorApplicationDrydock extends PhabricatorApplication { return true; } + public function getHelpURI() { + return PhabricatorEnv::getDoclink('Drydock User Guide'); + } + public function getRoutes() { return array( '/drydock/' => array( diff --git a/src/applications/fact/application/PhabricatorApplicationFact.php b/src/applications/fact/application/PhabricatorApplicationFact.php index 0436594b50..3a3439c7bc 100644 --- a/src/applications/fact/application/PhabricatorApplicationFact.php +++ b/src/applications/fact/application/PhabricatorApplicationFact.php @@ -3,7 +3,7 @@ final class PhabricatorApplicationFact extends PhabricatorApplication { public function getShortDescription() { - return 'Analyze Data'; + return pht('Chart and Analyze Data'); } public function getName() { diff --git a/src/applications/feed/application/PhabricatorApplicationFeed.php b/src/applications/feed/application/PhabricatorApplicationFeed.php index 21c8092e3d..b30da72fe5 100644 --- a/src/applications/feed/application/PhabricatorApplicationFeed.php +++ b/src/applications/feed/application/PhabricatorApplicationFeed.php @@ -7,7 +7,7 @@ final class PhabricatorApplicationFeed extends PhabricatorApplication { } public function getShortDescription() { - return pht('Review Activity'); + return pht('Review Recent Activity'); } public function getIconName() { diff --git a/src/applications/flag/application/PhabricatorApplicationFlags.php b/src/applications/flag/application/PhabricatorApplicationFlags.php index b7701340b6..e9bee801d1 100644 --- a/src/applications/flag/application/PhabricatorApplicationFlags.php +++ b/src/applications/flag/application/PhabricatorApplicationFlags.php @@ -3,7 +3,7 @@ final class PhabricatorApplicationFlags extends PhabricatorApplication { public function getShortDescription() { - return pht('Reminders'); + return pht('Personal Bookmarks and Reminders'); } public function getBaseURI() { @@ -25,7 +25,7 @@ final class PhabricatorApplicationFlags extends PhabricatorApplication { } public function getApplicationGroup() { - return self::GROUP_ORGANIZATION; + return self::GROUP_UTILITIES; } public function loadStatus(PhabricatorUser $user) { diff --git a/src/applications/harbormaster/application/PhabricatorApplicationHarbormaster.php b/src/applications/harbormaster/application/PhabricatorApplicationHarbormaster.php index 4e3c61a64f..699f58077f 100644 --- a/src/applications/harbormaster/application/PhabricatorApplicationHarbormaster.php +++ b/src/applications/harbormaster/application/PhabricatorApplicationHarbormaster.php @@ -7,7 +7,7 @@ final class PhabricatorApplicationHarbormaster extends PhabricatorApplication { } public function getShortDescription() { - return pht('Continuous Build'); + return pht('Builds and Continuous Integration'); } public function getIconName() { diff --git a/src/applications/legalpad/application/PhabricatorApplicationLegalpad.php b/src/applications/legalpad/application/PhabricatorApplicationLegalpad.php index 7b9dd4b0b5..999e20b646 100644 --- a/src/applications/legalpad/application/PhabricatorApplicationLegalpad.php +++ b/src/applications/legalpad/application/PhabricatorApplicationLegalpad.php @@ -7,7 +7,7 @@ final class PhabricatorApplicationLegalpad extends PhabricatorApplication { } public function getShortDescription() { - return pht('Legal Documents'); + return pht('Agreements and Signatures'); } public function getIconName() { diff --git a/src/applications/meta/application/PhabricatorApplicationApplications.php b/src/applications/meta/application/PhabricatorApplicationApplications.php index 66c611406c..847e0f2c2b 100644 --- a/src/applications/meta/application/PhabricatorApplicationApplications.php +++ b/src/applications/meta/application/PhabricatorApplicationApplications.php @@ -11,7 +11,7 @@ final class PhabricatorApplicationApplications extends PhabricatorApplication { } public function getShortDescription() { - return 'Installed Applications'; + return pht('Explore More Applications'); } public function getIconName() { @@ -26,7 +26,7 @@ final class PhabricatorApplicationApplications extends PhabricatorApplication { return self::GROUP_ADMIN; } - public function getRoutes() { + public function getRoutes() { return array( '/applications/' => array( '(?:query/(?P[^/]+)/)?' => @@ -38,7 +38,6 @@ final class PhabricatorApplicationApplications extends PhabricatorApplication { '(?P\w+)/(?Pinstall|uninstall)/' => 'PhabricatorApplicationUninstallController', ), - ); } diff --git a/src/applications/meta/controller/PhabricatorApplicationDetailViewController.php b/src/applications/meta/controller/PhabricatorApplicationDetailViewController.php index b2cc713181..1dacee6761 100644 --- a/src/applications/meta/controller/PhabricatorApplicationDetailViewController.php +++ b/src/applications/meta/controller/PhabricatorApplicationDetailViewController.php @@ -1,10 +1,14 @@ application = $data['application']; } @@ -61,16 +65,37 @@ final class PhabricatorApplicationDetailViewController $viewer = $this->getRequest()->getUser(); - $properties = id(new PHUIPropertyListView()) - ->addProperty(pht('Description'), $application->getShortDescription()); + $properties = id(new PHUIPropertyListView()); $properties->setActionList($actions); + $properties->addProperty( + pht('Description'), + $application->getShortDescription()); + + if ($application->getFlavorText()) { + $properties->addProperty( + null, + phutil_tag('em', array(), $application->getFlavorText())); + } + if ($application->isBeta()) { $properties->addProperty( pht('Release'), pht('Beta')); } + $overview = $application->getOverview(); + if ($overview) { + $properties->addSectionHeader( + pht('Overview'), + PHUIPropertyListView::ICON_SUMMARY); + $properties->addTextContent( + PhabricatorMarkupEngine::renderOneObject( + id(new PhabricatorMarkupOneOff())->setContent($overview), + 'default', + $viewer)); + } + $descriptions = PhabricatorPolicyQuery::renderPolicyDescriptions( $viewer, $application); @@ -94,6 +119,14 @@ final class PhabricatorApplicationDetailViewController ->setUser($user) ->setObjectURI($this->getRequest()->getRequestURI()); + if ($selected->getHelpURI()) { + $view->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Help / Documentation')) + ->setIcon('fa-life-ring') + ->setHref($selected->getHelpURI())); + } + $can_edit = PhabricatorPolicyFilter::hasCapability( $user, $selected, diff --git a/src/applications/meta/controller/PhabricatorApplicationEditController.php b/src/applications/meta/controller/PhabricatorApplicationEditController.php index aa4952205b..5d1ac1e185 100644 --- a/src/applications/meta/controller/PhabricatorApplicationEditController.php +++ b/src/applications/meta/controller/PhabricatorApplicationEditController.php @@ -1,10 +1,14 @@ application = $data['application']; } diff --git a/src/applications/meta/controller/PhabricatorApplicationUninstallController.php b/src/applications/meta/controller/PhabricatorApplicationUninstallController.php index 8445526a04..052ef30222 100644 --- a/src/applications/meta/controller/PhabricatorApplicationUninstallController.php +++ b/src/applications/meta/controller/PhabricatorApplicationUninstallController.php @@ -6,6 +6,10 @@ final class PhabricatorApplicationUninstallController private $application; private $action; + public function shouldRequireAdmin() { + return true; + } + public function willProcessRequest(array $data) { $this->application = $data['application']; $this->action = $data['action']; diff --git a/src/applications/meta/controller/PhabricatorApplicationsController.php b/src/applications/meta/controller/PhabricatorApplicationsController.php index 69f5bd03dd..e5b035bab4 100644 --- a/src/applications/meta/controller/PhabricatorApplicationsController.php +++ b/src/applications/meta/controller/PhabricatorApplicationsController.php @@ -2,10 +2,6 @@ abstract class PhabricatorApplicationsController extends PhabricatorController { - public function shouldRequireAdmin() { - return true; - } - public function buildSideNavView($for_app = false) { $user = $this->getRequest()->getUser(); diff --git a/src/applications/meta/controller/PhabricatorApplicationsListController.php b/src/applications/meta/controller/PhabricatorApplicationsListController.php index 5815f7cff2..9bcb845768 100644 --- a/src/applications/meta/controller/PhabricatorApplicationsListController.php +++ b/src/applications/meta/controller/PhabricatorApplicationsListController.php @@ -5,6 +5,10 @@ final class PhabricatorApplicationsListController private $queryKey; + public function shouldAllowPublic() { + return true; + } + public function willProcessRequest(array $data) { $this->queryKey = idx($data, 'queryKey'); } diff --git a/src/applications/meta/query/PhabricatorAppSearchEngine.php b/src/applications/meta/query/PhabricatorAppSearchEngine.php index a83a84e566..4f26a80859 100644 --- a/src/applications/meta/query/PhabricatorAppSearchEngine.php +++ b/src/applications/meta/query/PhabricatorAppSearchEngine.php @@ -25,6 +25,9 @@ final class PhabricatorAppSearchEngine $saved->setParameter( 'firstParty', $this->readBoolFromRequest($request, 'firstParty')); + $saved->setParameter( + 'launchable', + $this->readBoolFromRequest($request, 'launchable')); return $saved; } @@ -54,6 +57,11 @@ final class PhabricatorAppSearchEngine $query->withFirstParty($first_party); } + $launchable = $saved->getParameter('launchable'); + if ($launchable !== null) { + $query->withLaunchable($launchable); + } + return $query; } @@ -99,6 +107,17 @@ final class PhabricatorAppSearchEngine '' => pht('Show All Applications'), 'true' => pht('Show First-Party Applications'), 'false' => pht('Show Third-Party Applications'), + ))) + ->appendChild( + id(new AphrontFormSelectControl()) + ->setLabel(pht('Launchable')) + ->setName('launchable') + ->setValue($this->getBoolFromQuery($saved, 'launchable')) + ->setOptions( + array( + '' => pht('Show All Applications'), + 'true' => pht('Show Launchable Applications'), + 'false' => pht('Show Non-Launchable Applications'), ))); } @@ -109,6 +128,7 @@ final class PhabricatorAppSearchEngine public function getBuiltinQueryNames() { $names = array( + 'launcher' => pht('Launcher'), 'all' => pht('All Applications'), ); @@ -121,6 +141,10 @@ final class PhabricatorAppSearchEngine $query->setQueryKey($query_key); switch ($query_key) { + case 'launcher': + return $query + ->setParameter('installed', true) + ->setParameter('launchable', true); case 'all': return $query; } @@ -129,33 +153,93 @@ final class PhabricatorAppSearchEngine } protected function renderResultList( - array $applications, + array $all_applications, PhabricatorSavedQuery $query, array $handle) { - assert_instances_of($applications, 'PhabricatorApplication'); + assert_instances_of($all_applications, 'PhabricatorApplication'); - $list = new PHUIObjectItemListView(); + $all_applications = msort($all_applications, 'getName'); - $applications = msort($applications, 'getName'); - - foreach ($applications as $application) { - $item = id(new PHUIObjectItemView()) - ->setHeader($application->getName()) - ->setHref('/applications/view/'.get_class($application).'/') - ->addAttribute($application->getShortDescription()); - - if (!$application->isInstalled()) { - $item->addIcon('delete', pht('Uninstalled')); - } - - if ($application->isBeta()) { - $item->addIcon('lint-warning', pht('Beta')); - } - - $list->addItem($item); + if ($query->getQueryKey() == 'launcher') { + $groups = mgroup($all_applications, 'getApplicationGroup'); + } else { + $groups = array($all_applications); } - return $list; + $group_names = PhabricatorApplication::getApplicationGroups(); + $groups = array_select_keys($groups, array_keys($group_names)) + $groups; + + $results = array(); + foreach ($groups as $group => $applications) { + if (count($groups) > 1) { + $results[] = phutil_tag( + 'h1', + array( + 'class' => 'launcher-header', + ), + idx($group_names, $group, $group)); + } + + $list = new PHUIObjectItemListView(); + $list->addClass('phui-object-item-launcher-list'); + + foreach ($applications as $application) { + $icon = $application->getIconName(); + if (!$icon) { + $icon = 'application'; + } + + // TODO: This sheet doesn't work the same way other sheets do so it + // ends up with the wrong classes if we try to use PHUIIconView. This + // is probably all changing in the redesign anyway. + + $icon_view = javelin_tag( + 'span', + array( + 'class' => 'phui-icon-view '. + 'sprite-apps-large apps-'.$icon.'-dark-large', + 'aural' => false, + ), + ''); + + $description = phutil_tag( + 'div', + array( + 'style' => 'white-space: nowrap; '. + 'overflow: hidden; '. + 'text-overflow: ellipsis;', + ), + $application->getShortDescription()); + + $item = id(new PHUIObjectItemView()) + ->setHeader($application->getName()) + ->setImageIcon($icon_view) + ->addAttribute($description) + ->addAction( + id(new PHUIListItemView()) + ->setName(pht('Help/Options')) + ->setIcon('fa-cog') + ->setHref('/applications/view/'.get_class($application).'/')); + + if ($application->getBaseURI()) { + $item->setHref($application->getBaseURI()); + } + + if (!$application->isInstalled()) { + $item->addIcon('delete', pht('Uninstalled')); + } + + if ($application->isBeta()) { + $item->addIcon('fa-star-half-o grey', pht('Beta')); + } + + $list->addItem($item); + } + + $results[] = $list; + } + + return $results; } } diff --git a/src/applications/meta/query/PhabricatorApplicationQuery.php b/src/applications/meta/query/PhabricatorApplicationQuery.php index ca14d6954a..366a29d422 100644 --- a/src/applications/meta/query/PhabricatorApplicationQuery.php +++ b/src/applications/meta/query/PhabricatorApplicationQuery.php @@ -9,6 +9,7 @@ final class PhabricatorApplicationQuery private $nameContains; private $unlisted; private $classes; + private $launchable; private $phids; const ORDER_APPLICATION = 'order:application'; @@ -41,6 +42,11 @@ final class PhabricatorApplicationQuery return $this; } + public function withLaunchable($launchable) { + $this->launchable = $launchable; + return $this; + } + public function withClasses(array $classes) { $this->classes = $classes; return $this; @@ -117,6 +123,15 @@ final class PhabricatorApplicationQuery } } + if ($this->launchable !== null) { + foreach ($apps as $key => $app) { + if ($app->shouldAppearInLaunchView() != $this->launchable) { + unset($apps[$key]); + } + } + } + + switch ($this->order) { case self::ORDER_NAME: $apps = msort($apps, 'getName'); diff --git a/src/applications/metamta/application/PhabricatorApplicationMetaMTA.php b/src/applications/metamta/application/PhabricatorApplicationMetaMTA.php index 844eca2ec0..70605eb1a1 100644 --- a/src/applications/metamta/application/PhabricatorApplicationMetaMTA.php +++ b/src/applications/metamta/application/PhabricatorApplicationMetaMTA.php @@ -2,14 +2,14 @@ final class PhabricatorApplicationMetaMTA extends PhabricatorApplication { - public function getBaseURI() { - return '/mail/'; - } - public function getIconName() { return 'metamta'; } + public function getShortDescription() { + return pht('Delivers Mail'); + } + public function getFlavorText() { return pht('Yo dawg, we heard you like MTAs.'); } diff --git a/src/applications/notification/application/PhabricatorApplicationNotifications.php b/src/applications/notification/application/PhabricatorApplicationNotifications.php index a4925c107d..1de16b76cd 100644 --- a/src/applications/notification/application/PhabricatorApplicationNotifications.php +++ b/src/applications/notification/application/PhabricatorApplicationNotifications.php @@ -7,7 +7,7 @@ final class PhabricatorApplicationNotifications extends PhabricatorApplication { } public function getShortDescription() { - return pht('Beep Beep Bloop'); + return pht('Real-Time Updates and Alerts'); } public function getRoutes() { diff --git a/src/applications/nuance/application/PhabricatorApplicationNuance.php b/src/applications/nuance/application/PhabricatorApplicationNuance.php index ac962b1982..5bf137b814 100644 --- a/src/applications/nuance/application/PhabricatorApplicationNuance.php +++ b/src/applications/nuance/application/PhabricatorApplicationNuance.php @@ -27,6 +27,10 @@ final class PhabricatorApplicationNuance extends PhabricatorApplication { return '/nuance/'; } + public function getShortDescription() { + return pht('High-Volume Task Queues'); + } + public function getRoutes() { return array( '/nuance/' => array( diff --git a/src/applications/oauthserver/application/PhabricatorApplicationOAuthServer.php b/src/applications/oauthserver/application/PhabricatorApplicationOAuthServer.php index 8510f8c5f6..399367436f 100644 --- a/src/applications/oauthserver/application/PhabricatorApplicationOAuthServer.php +++ b/src/applications/oauthserver/application/PhabricatorApplicationOAuthServer.php @@ -7,7 +7,7 @@ final class PhabricatorApplicationOAuthServer extends PhabricatorApplication { } public function getShortDescription() { - return pht('OAuth Provider'); + return pht('OAuth Login Provider'); } public function getIconName() { @@ -23,13 +23,17 @@ final class PhabricatorApplicationOAuthServer extends PhabricatorApplication { } public function getApplicationGroup() { - return self::GROUP_UTILITIES; + return self::GROUP_ADMIN; } public function isBeta() { return true; } + public function getHelpURI() { + return PhabricatorEnv::getDoclink('Using the Phabricator OAuth Server'); + } + public function getRoutes() { return array( '/oauthserver/' => array( diff --git a/src/applications/owners/application/PhabricatorApplicationOwners.php b/src/applications/owners/application/PhabricatorApplicationOwners.php index ed80bf0b45..6412772236 100644 --- a/src/applications/owners/application/PhabricatorApplicationOwners.php +++ b/src/applications/owners/application/PhabricatorApplicationOwners.php @@ -11,7 +11,7 @@ final class PhabricatorApplicationOwners extends PhabricatorApplication { } public function getShortDescription() { - return pht('Group Source Code'); + return pht('Track Ownership of Source Code'); } public function getTitleGlyph() { @@ -27,7 +27,7 @@ final class PhabricatorApplicationOwners extends PhabricatorApplication { } public function getApplicationGroup() { - return self::GROUP_ORGANIZATION; + return self::GROUP_UTILITIES; } public function getRoutes() { diff --git a/src/applications/passphrase/application/PhabricatorApplicationPassphrase.php b/src/applications/passphrase/application/PhabricatorApplicationPassphrase.php index 2632106044..dedeb505b8 100644 --- a/src/applications/passphrase/application/PhabricatorApplicationPassphrase.php +++ b/src/applications/passphrase/application/PhabricatorApplicationPassphrase.php @@ -7,7 +7,7 @@ final class PhabricatorApplicationPassphrase extends PhabricatorApplication { } public function getShortDescription() { - return pht('Credential Management'); + return pht('Store Passwords and Credentials'); } public function getIconName() { diff --git a/src/applications/paste/application/PhabricatorApplicationPaste.php b/src/applications/paste/application/PhabricatorApplicationPaste.php index 0e99441e5d..5ba1f211fc 100644 --- a/src/applications/paste/application/PhabricatorApplicationPaste.php +++ b/src/applications/paste/application/PhabricatorApplicationPaste.php @@ -18,6 +18,10 @@ final class PhabricatorApplicationPaste extends PhabricatorApplication { return self::GROUP_UTILITIES; } + public function getShortDescription() { + return pht('Share Text Snippets'); + } + public function getRemarkupRules() { return array( new PhabricatorPasteRemarkupRule(), diff --git a/src/applications/people/application/PhabricatorApplicationPeople.php b/src/applications/people/application/PhabricatorApplicationPeople.php index 2b89dc4d2c..d387b0f882 100644 --- a/src/applications/people/application/PhabricatorApplicationPeople.php +++ b/src/applications/people/application/PhabricatorApplicationPeople.php @@ -3,7 +3,7 @@ final class PhabricatorApplicationPeople extends PhabricatorApplication { public function getShortDescription() { - return pht('User Accounts'); + return pht('User Accounts and Profiles'); } public function getBaseURI() { diff --git a/src/applications/phlux/application/PhabricatorApplicationPhlux.php b/src/applications/phlux/application/PhabricatorApplicationPhlux.php index 85c1699cb3..c6e42598cc 100644 --- a/src/applications/phlux/application/PhabricatorApplicationPhlux.php +++ b/src/applications/phlux/application/PhabricatorApplicationPhlux.php @@ -7,7 +7,7 @@ final class PhabricatorApplicationPhlux extends PhabricatorApplication { } public function getShortDescription() { - return pht('Configuration Store'); + return pht('Key/Value Configuration Store'); } public function getIconName() { diff --git a/src/applications/pholio/application/PhabricatorApplicationPholio.php b/src/applications/pholio/application/PhabricatorApplicationPholio.php index 96f113cba3..500ee5098b 100644 --- a/src/applications/pholio/application/PhabricatorApplicationPholio.php +++ b/src/applications/pholio/application/PhabricatorApplicationPholio.php @@ -7,7 +7,7 @@ final class PhabricatorApplicationPholio extends PhabricatorApplication { } public function getShortDescription() { - return pht('Design Review'); + return pht('Review Mocks and Design'); } public function getIconName() { diff --git a/src/applications/phortune/application/PhabricatorApplicationPhortune.php b/src/applications/phortune/application/PhabricatorApplicationPhortune.php index fe08ef4487..ab22fbde88 100644 --- a/src/applications/phortune/application/PhabricatorApplicationPhortune.php +++ b/src/applications/phortune/application/PhabricatorApplicationPhortune.php @@ -7,7 +7,7 @@ final class PhabricatorApplicationPhortune extends PhabricatorApplication { } public function getShortDescription() { - return pht('Account and Billing'); + return pht('Accounts and Billing'); } public function getIconName() { diff --git a/src/applications/phrequent/application/PhabricatorApplicationPhrequent.php b/src/applications/phrequent/application/PhabricatorApplicationPhrequent.php index 35f2dd9fd9..4bcccef60d 100644 --- a/src/applications/phrequent/application/PhabricatorApplicationPhrequent.php +++ b/src/applications/phrequent/application/PhabricatorApplicationPhrequent.php @@ -3,7 +3,7 @@ final class PhabricatorApplicationPhrequent extends PhabricatorApplication { public function getShortDescription() { - return pht('Track Time'); + return pht('Track Time Spent'); } public function getBaseURI() { @@ -19,7 +19,7 @@ final class PhabricatorApplicationPhrequent extends PhabricatorApplication { } public function getApplicationGroup() { - return self::GROUP_ORGANIZATION; + return self::GROUP_UTILITIES; } public function getApplicationOrder() { diff --git a/src/applications/ponder/application/PhabricatorApplicationPonder.php b/src/applications/ponder/application/PhabricatorApplicationPonder.php index 220750b558..0821533460 100644 --- a/src/applications/ponder/application/PhabricatorApplicationPonder.php +++ b/src/applications/ponder/application/PhabricatorApplicationPonder.php @@ -7,7 +7,7 @@ final class PhabricatorApplicationPonder extends PhabricatorApplication { } public function getShortDescription() { - return pht('Find Answers'); + return pht('Questions and Answers'); } public function getIconName() { diff --git a/src/applications/project/application/PhabricatorApplicationProject.php b/src/applications/project/application/PhabricatorApplicationProject.php index 22e016c285..60c13fb62e 100644 --- a/src/applications/project/application/PhabricatorApplicationProject.php +++ b/src/applications/project/application/PhabricatorApplicationProject.php @@ -7,7 +7,7 @@ final class PhabricatorApplicationProject extends PhabricatorApplication { } public function getShortDescription() { - return pht('Organize Work'); + return pht('Create Groups, Tags, and Projects'); } public function getBaseURI() { diff --git a/src/applications/releeph/application/PhabricatorApplicationReleeph.php b/src/applications/releeph/application/PhabricatorApplicationReleeph.php index 3876470ff5..79f7a24961 100644 --- a/src/applications/releeph/application/PhabricatorApplicationReleeph.php +++ b/src/applications/releeph/application/PhabricatorApplicationReleeph.php @@ -7,7 +7,7 @@ final class PhabricatorApplicationReleeph extends PhabricatorApplication { } public function getShortDescription() { - return pht('Release Branches'); + return pht('Pull Requests'); } public function getBaseURI() { diff --git a/src/applications/repository/application/PhabricatorApplicationRepositories.php b/src/applications/repository/application/PhabricatorApplicationRepositories.php index 0afce533b4..e2caea3527 100644 --- a/src/applications/repository/application/PhabricatorApplicationRepositories.php +++ b/src/applications/repository/application/PhabricatorApplicationRepositories.php @@ -14,7 +14,7 @@ final class PhabricatorApplicationRepositories extends PhabricatorApplication { } public function getShortDescription() { - return 'Track Repositories'; + return pht('(Deprecated)'); } public function getTitleGlyph() { diff --git a/src/applications/search/application/PhabricatorApplicationSearch.php b/src/applications/search/application/PhabricatorApplicationSearch.php index eb2199947b..c1b73f7446 100644 --- a/src/applications/search/application/PhabricatorApplicationSearch.php +++ b/src/applications/search/application/PhabricatorApplicationSearch.php @@ -11,7 +11,7 @@ final class PhabricatorApplicationSearch extends PhabricatorApplication { } public function getShortDescription() { - return pht('Search & Find'); + return pht('Full-Text Search'); } public function getFlavorText() { diff --git a/src/applications/settings/application/PhabricatorApplicationSettings.php b/src/applications/settings/application/PhabricatorApplicationSettings.php index 65ad9505ad..a4028f6b9a 100644 --- a/src/applications/settings/application/PhabricatorApplicationSettings.php +++ b/src/applications/settings/application/PhabricatorApplicationSettings.php @@ -7,7 +7,7 @@ final class PhabricatorApplicationSettings extends PhabricatorApplication { } public function getShortDescription() { - return 'User Preferences'; + return pht('User Preferences'); } public function getIconName() { @@ -18,6 +18,10 @@ final class PhabricatorApplicationSettings extends PhabricatorApplication { return false; } + public function shouldAppearInLaunchView() { + return false; + } + public function getRoutes() { return array( '/settings/' => array( diff --git a/src/applications/tokens/application/PhabricatorApplicationTokens.php b/src/applications/tokens/application/PhabricatorApplicationTokens.php index 39d665e7b4..dd1a77d2d0 100644 --- a/src/applications/tokens/application/PhabricatorApplicationTokens.php +++ b/src/applications/tokens/application/PhabricatorApplicationTokens.php @@ -19,7 +19,7 @@ final class PhabricatorApplicationTokens extends PhabricatorApplication { } public function getShortDescription() { - return pht('Acquire Trinkets'); + return pht('Award and Acquire Trinkets'); } public function getApplicationGroup() { diff --git a/src/applications/uiexample/application/PhabricatorApplicationUIExamples.php b/src/applications/uiexample/application/PhabricatorApplicationUIExamples.php index e74c1138ad..e7774432a2 100644 --- a/src/applications/uiexample/application/PhabricatorApplicationUIExamples.php +++ b/src/applications/uiexample/application/PhabricatorApplicationUIExamples.php @@ -7,7 +7,7 @@ final class PhabricatorApplicationUIExamples extends PhabricatorApplication { } public function getShortDescription() { - return 'Developer UI Examples'; + return pht('Phabricator Developer UI Examples'); } public function getIconName() { diff --git a/src/view/phui/PHUIObjectItemView.php b/src/view/phui/PHUIObjectItemView.php index f888207454..80592fe5f9 100644 --- a/src/view/phui/PHUIObjectItemView.php +++ b/src/view/phui/PHUIObjectItemView.php @@ -21,6 +21,7 @@ final class PHUIObjectItemView extends AphrontTagView { private $imageURI; private $state; private $fontIcon; + private $imageIcon; const AGE_FRESH = 'fresh'; const AGE_STALE = 'stale'; @@ -115,6 +116,15 @@ final class PHUIObjectItemView extends AphrontTagView { return $this->imageURI; } + public function setImageIcon($image_icon) { + $this->imageIcon = $image_icon; + return $this; + } + + public function getImageIcon() { + return $this->imageIcon; + } + public function setState($state) { $this->state = $state; switch ($state) { @@ -288,6 +298,10 @@ final class PHUIObjectItemView extends AphrontTagView { $item_classes[] = 'phui-object-item-with-image'; } + if ($this->getImageIcon()) { + $item_classes[] = 'phui-object-item-with-image-icon'; + } + if ($this->fontIcon) { $item_classes[] = 'phui-object-item-with-ficon'; } @@ -520,6 +534,22 @@ final class PHUIObjectItemView extends AphrontTagView { 'style' => 'background-image: url('.$this->getImageURI().')', ), ''); + } else if ($this->getImageIcon()) { + $image = phutil_tag( + 'div', + array( + 'class' => 'phui-object-item-image-icon', + ), + $this->getImageIcon()); + } + + if ($image && $this->href) { + $image = phutil_tag( + 'a', + array( + 'href' => $this->href, + ), + $image); } $ficon = null; diff --git a/webroot/rsrc/css/phui/phui-object-item-list-view.css b/webroot/rsrc/css/phui/phui-object-item-list-view.css index e4055541e6..d9787f2c51 100644 --- a/webroot/rsrc/css/phui/phui-object-item-list-view.css +++ b/webroot/rsrc/css/phui/phui-object-item-list-view.css @@ -671,3 +671,54 @@ border: none; border-bottom: 1px solid {$thinblueborder}; } + + +/* - Launcher List ---------------------------------------------------------- */ + +.launcher-header { + margin: 8px 16px -4px; + clear: both; + color: {$darkbluetext}; +} + +.launcher-header:nth-of-type(1) { + margin-top: 24px; +} + +.phui-object-item-launcher-list { + overflow: hidden; +} + +.device-desktop .phui-object-item-launcher-list .phui-object-item { + width: 32.333%; + float: left; + margin-right: 1%; + box-sizing: border-box; +} + +.phui-object-item-image-icon { + background: none; +} + +.phui-object-item-image-icon { + width: 30px; + height: 30px; + margin: 4px 4px 4px 4px; + position: absolute; +} + +.phui-object-item-image-icon .phui-icon-view { + position: absolute; + width: 28px; + height: 28px; + left: 6px; + top: 6px; +} + +.phui-object-item-with-image-icon .phui-object-item-frame { + min-height: 48px; +} + +.phui-object-item-with-image-icon .phui-object-item-content-box { + margin-left: 44px; +} From 91109805a50ce828b99a81567f1bd3e8d24a1a56 Mon Sep 17 00:00:00 2001 From: epriestley Date: Thu, 29 May 2014 12:19:43 -0700 Subject: [PATCH 20/21] Leafy minerals. --- resources/celerity/map.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/resources/celerity/map.php b/resources/celerity/map.php index 86fc00d4ce..28c802f2ab 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -7,7 +7,7 @@ return array( 'names' => array( - 'core.pkg.css' => 'c404fb89', + 'core.pkg.css' => '8ecc2a14', 'core.pkg.js' => '7db41c19', 'darkconsole.pkg.js' => 'ca8671ce', 'differential.pkg.css' => 'fbf57382', @@ -136,7 +136,7 @@ return array( 'rsrc/css/phui/phui-info-panel.css' => '27ea50a1', 'rsrc/css/phui/phui-list.css' => 'bf15683f', 'rsrc/css/phui/phui-object-box.css' => 'ce92d8ec', - 'rsrc/css/phui/phui-object-item-list-view.css' => '16003f41', + 'rsrc/css/phui/phui-object-item-list-view.css' => '15c582b1', 'rsrc/css/phui/phui-pinboard-view.css' => '874c22f9', 'rsrc/css/phui/phui-property-list-view.css' => '2f7199e8', 'rsrc/css/phui/phui-remarkup-preview.css' => '19ad512b', @@ -482,7 +482,7 @@ return array( 'rsrc/js/phuix/PHUIXActionListView.js' => 'b5c256b8', 'rsrc/js/phuix/PHUIXActionView.js' => '6e8cefa4', 'rsrc/js/phuix/PHUIXDropdownMenu.js' => 'bd4c8dca', - 'rsrc/swf/aphlict.swf' => 'abac967d', + 'rsrc/swf/aphlict.swf' => '731d14a6', ), 'symbols' => array( @@ -766,7 +766,7 @@ return array( 'phui-info-panel-css' => '27ea50a1', 'phui-list-view-css' => 'bf15683f', 'phui-object-box-css' => 'ce92d8ec', - 'phui-object-item-list-view-css' => '16003f41', + 'phui-object-item-list-view-css' => '15c582b1', 'phui-pinboard-view-css' => '874c22f9', 'phui-property-list-view-css' => '2f7199e8', 'phui-remarkup-preview-css' => '19ad512b', From e05f427f3dd19b9ade562aad83d1e2b4dab20bce Mon Sep 17 00:00:00 2001 From: Joshua Spence Date: Thu, 29 May 2014 14:47:15 -0700 Subject: [PATCH 21/21] Compress the Aphlict client SWF. Summary: Remove the `-debug=true` flags from the script used to build the Aplhict client SWF. Test Plan: **Before** ``` > du -h webroot/rsrc/swf/aphlict.swf 20K ``` **After** ``` > du -h webroot/rsrc/swf/aphlict.swf 16K ``` Reviewers: epriestley, #blessed_reviewers Reviewed By: epriestley, #blessed_reviewers Subscribers: epriestley, Korvin Differential Revision: https://secure.phabricator.com/D9333 --- .../aphlict/client/build_aphlict_client.sh | 1 - webroot/rsrc/swf/aphlict.swf | Bin 9213 -> 5315 bytes 2 files changed, 1 deletion(-) diff --git a/support/aphlict/client/build_aphlict_client.sh b/support/aphlict/client/build_aphlict_client.sh index f081c9f0d2..0d2e4ae122 100755 --- a/support/aphlict/client/build_aphlict_client.sh +++ b/support/aphlict/client/build_aphlict_client.sh @@ -15,7 +15,6 @@ $MXMLC \ -default-background-color=0x444444 \ -default-size=500,500 \ -warnings=true \ - -debug=true \ -source-path=$ROOT/externals/vegas/src \ -static-link-runtime-shared-libraries=true \ $BASEDIR/src/AphlictClient.as diff --git a/webroot/rsrc/swf/aphlict.swf b/webroot/rsrc/swf/aphlict.swf index bccd0f0d47070f7c0e31d73d8bc76a773f209dcf..cee18c7dc6ebe486fa90ea29721197e11431788a 100644 GIT binary patch literal 5315 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 VU9p<|TiVY5+s9my{{ySMFv?EqEmQyi literal 9213 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 T7qYLRTR(h}dO-O<`+!RI$|eAh
{$text}{$file}:{$line}{$where}()