Page MenuHomePhabricator
Paste P1834

space-switching-ui.patch
ActivePublic

Authored by devurandom on Jul 28 2015, 4:59 PM.
Tags
Referenced Files
F702492: space-switching-ui.patch
Aug 11 2015, 5:13 PM
F673181: space-switching-ui.patch
Jul 28 2015, 4:59 PM
Subscribers
None
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
index d98c746..5650350 100644
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -2230,6 +2230,7 @@ phutil_register_library_map(array(
'PhabricatorMailTarget' => 'applications/metamta/replyhandler/PhabricatorMailTarget.php',
'PhabricatorMailgunConfigOptions' => 'applications/config/option/PhabricatorMailgunConfigOptions.php',
'PhabricatorMainMenuSearchView' => 'view/page/menu/PhabricatorMainMenuSearchView.php',
+ 'PhabricatorMainMenuSpacesView' => 'view/page/menu/PhabricatorMainMenuSpacesView.php',
'PhabricatorMainMenuView' => 'view/page/menu/PhabricatorMainMenuView.php',
'PhabricatorManagementWorkflow' => 'infrastructure/management/PhabricatorManagementWorkflow.php',
'PhabricatorManiphestApplication' => 'applications/maniphest/application/PhabricatorManiphestApplication.php',
@@ -6099,6 +6100,7 @@ phutil_register_library_map(array(
'PhabricatorMailTarget' => 'Phobject',
'PhabricatorMailgunConfigOptions' => 'PhabricatorApplicationConfigOptions',
'PhabricatorMainMenuSearchView' => 'AphrontView',
+ 'PhabricatorMainMenuSpacesView' => 'AphrontView',
'PhabricatorMainMenuView' => 'AphrontView',
'PhabricatorManagementWorkflow' => 'PhutilArgumentWorkflow',
'PhabricatorManiphestApplication' => 'PhabricatorApplication',
diff --git a/src/applications/maniphest/storage/ManiphestTask.php b/src/applications/maniphest/storage/ManiphestTask.php
index 7fbc806..ec2a2d1 100644
--- a/src/applications/maniphest/storage/ManiphestTask.php
+++ b/src/applications/maniphest/storage/ManiphestTask.php
@@ -52,13 +52,18 @@ final class ManiphestTask extends ManiphestDAO
$view_policy = $app->getPolicy(ManiphestDefaultViewCapability::CAPABILITY);
$edit_policy = $app->getPolicy(ManiphestDefaultEditCapability::CAPABILITY);
+ $current_space_key = PhabricatorUserPreferences::PREFERENCE_CURRENT_SPACE;
+ $space_phid = $actor->loadPreferences()->getPreference(
+ $current_space_key,
+ $actor->getDefaultSpacePHID());
+
return id(new ManiphestTask())
->setStatus(ManiphestTaskStatus::getDefaultStatus())
->setPriority(ManiphestTaskPriority::getDefaultPriority())
->setAuthorPHID($actor->getPHID())
->setViewPolicy($view_policy)
->setEditPolicy($edit_policy)
- ->setSpacePHID($actor->getDefaultSpacePHID())
+ ->setSpacePHID($space_phid)
->attachProjectPHIDs(array())
->attachSubscriberPHIDs(array());
}
diff --git a/src/applications/settings/storage/PhabricatorUserPreferences.php b/src/applications/settings/storage/PhabricatorUserPreferences.php
index 1527f28..8c876b4 100644
--- a/src/applications/settings/storage/PhabricatorUserPreferences.php
+++ b/src/applications/settings/storage/PhabricatorUserPreferences.php
@@ -41,6 +41,8 @@ final class PhabricatorUserPreferences extends PhabricatorUserDAO {
const PREFERENCE_RESOURCE_POSTPROCESSOR = 'resource-postprocessor';
const PREFERENCE_DESKTOP_NOTIFICATIONS = 'desktop-notifications';
+ const PREFERENCE_CURRENT_SPACE = 'current-space';
+
// These are in an unusual order for historic reasons.
const MAILTAG_PREFERENCE_NOTIFY = 0;
const MAILTAG_PREFERENCE_EMAIL = 1;
diff --git a/src/view/page/menu/PhabricatorMainMenuView.php b/src/view/page/menu/PhabricatorMainMenuView.php
index 1dc8466..281d60d 100644
--- a/src/view/page/menu/PhabricatorMainMenuView.php
+++ b/src/view/page/menu/PhabricatorMainMenuView.php
@@ -52,6 +52,7 @@ final class PhabricatorMainMenuView extends AphrontView {
}
$search_menu = $this->renderPhabricatorSearchMenu();
+ $spaces_menu = $this->renderPhabricatorSpacesMenu();
if ($alerts) {
$alerts = javelin_tag(
@@ -98,6 +99,7 @@ final class PhabricatorMainMenuView extends AphrontView {
$aural,
$application_menu,
$search_menu,
+ $spaces_menu,
$menus,
));
}
@@ -149,6 +151,32 @@ final class PhabricatorMainMenuView extends AphrontView {
return $result;
}
+ private function renderSpaces() {
+ $user = $this->user;
+
+ $result = null;
+
+ $show_spaces = false;
+ if ($user->isLoggedIn()) {
+ $show_spaces = $user->isUserActivated();
+ }
+
+ if ($show_spaces) {
+ $spaces = new PhabricatorMainMenuSpacesView();
+ $spaces->setUser($user);
+
+ $result = $spaces;
+ }
+
+ if ($result) {
+ $result = id(new PHUIListItemView())
+ ->addClass('phabricator-main-menu-spaces')
+ ->appendChild($result);
+ }
+
+ return $result;
+ }
+
public function renderApplicationMenuButton($header_id) {
$button_id = celerity_generate_unique_node_id();
return javelin_tag(
@@ -251,6 +279,20 @@ final class PhabricatorMainMenuView extends AphrontView {
return $view;
}
+ private function renderPhabricatorSpacesMenu() {
+
+ $view = new PHUIListView();
+ $view->addClass('phabricator-dark-menu');
+ $view->addClass('phabricator-spaces-menu');
+
+ $spaces = $this->renderSpaces();
+ if ($spaces) {
+ $view->addMenuItem($spaces);
+ }
+
+ return $view;
+ }
+
private function renderPhabricatorLogo() {
$style_logo = null;
$custom_header = PhabricatorEnv::getEnvConfig('ui.custom-header');
diff --git a/webroot/rsrc/css/application/base/main-menu-view.css b/webroot/rsrc/css/application/base/main-menu-view.css
index b70e0b7..8c302ea 100644
--- a/webroot/rsrc/css/application/base/main-menu-view.css
+++ b/webroot/rsrc/css/application/base/main-menu-view.css
@@ -96,7 +96,8 @@
}
.phabricator-expand-application-menu,
-.phabricator-expand-search-menu {
+.phabricator-expand-search-menu,
+.phabricator-expand-spaces-menu {
float: right;
}
@@ -340,6 +341,125 @@ button.phabricator-main-menu-search-dropdown .caret:before {
+/* - Spaces --------------------------------------------------------------------
+
+ The main spaces selector in the menu bar.
+
+*/
+
+.device-desktop .phabricator-main-menu-spaces {
+ width: 220px;
+}
+
+.device .phabricator-main-menu-spaces {
+ height: 40px;
+}
+
+.phabricator-main-menu-spaces-container {
+ padding: 8px 0;
+ position: relative;
+ height: 24px;
+ margin: 0 8px;
+}
+
+.device .phabricator-main-menu-search-container {
+ padding: 4px 0;
+}
+
+.phabricator-main-menu-spaces button {
+// color: {$bluetext};
+ color: #fff;
+ position: absolute;
+ background: {$greybackground};
+ border: none;
+ outline: none;
+ box-shadow: none;
+ text-shadow: none;
+ min-width: 0;
+ height: 24px;
+ width: 28px;
+ top: 10px;
+ right: -6px;
+ margin: 0 8px 0 0;
+ padding: 0;
+ border-radius: 0;
+}
+
+.phabricator-main-menu-spaces button.phabricator-main-menu-spaces-dropdown {
+ position: absolute;
+ right: auto;
+ left: -45px;
+ width: 200px;
+ background: transparent;
+}
+
+.device-desktop .phabricator-main-menu-spaces
+ button.phabricator-main-menu-spaces-dropdown {
+ height: 28px;
+ top: 8px;
+ }
+
+.device-desktop .phabricator-main-menu-spaces
+ button.phabricator-main-menu-spaces-dropdown:hover .phui-icon-view {
+ color: #fff;
+}
+
+.device .phabricator-main-menu-spaces
+ button.phabricator-main-menu-spaces-dropdown {
+ left: 2px;
+ background: {$greybackground};
+}
+
+button.phabricator-main-menu-spaces-dropdown .caret:before {
+ content: "\f107";
+ font-family: FontAwesome;
+ color: {$hoverwhite};
+}
+
+.phabricator-main-menu-spaces button.phabricator-main-menu-spaces-dropdown
+ .phui-icon-view {
+ color: {$hoverwhite};
+ font-size: 15px;
+ top: 6px;
+ left: 8px;
+}
+
+.device
+ .phabricator-main-menu-spaces button.phabricator-main-menu-spaces-dropdown
+ .phui-icon-view {
+ color: {$bluetext};
+}
+
+.device button.phabricator-main-menu-spaces-dropdown .caret:before {
+ color: {$bluetext};
+}
+
+.phabricator-main-menu-spaces-dropdown .caret {
+ position: absolute;
+ right: 15px;
+ top: 5px;
+ border: none;
+ margin-top: 1px;
+}
+
+.phabricator-main-menu-spaces button:hover {
+ color: {$sky};
+}
+
+.device .phabricator-main-menu-spaces button {
+ top: 6px;
+ border-radius: 0;
+ height: 28px;
+ right: -6px;
+}
+
+.device .phabricator-application-menu-expanded.phabricator-spaces-menu-expanded
+ .phabricator-spaces-menu {
+ padding: 0;
+}
+
+
+
/* - Alert ---------------------------------------------------------------------
Alert menus are like icon menus but don't obey collapse rules.
@@ -460,6 +580,7 @@ button.phabricator-main-menu-search-dropdown .caret:before {
display: none;
}
+.device-desktop .phabricator-spaces-menu,
.device-desktop .phabricator-search-menu {
float: right;
}

Event Timeline

devurandom changed the title of this paste from untitled to space-switching-ui.patch.
devurandom updated the paste's language from autodetect to autodetect.
devurandom added a project: Spaces.

webroot/rsrc/js/core/behavior-spaces-switcher.js:

/**
 * @provides javelin-behavior-phabricator-spaces-switcher
 * @requires javelin-behavior
 *           javelin-typeahead-ondemand-source
 *           javelin-typeahead
 *           javelin-dom
 *           javelin-uri
 *           javelin-util
 *           javelin-stratcom
 *           phabricator-prefab
 */

JX.behavior('phabricator-spaces-switcher', function(config) {

  function updateIcon(button, data, new_icon) {
    var icon = JX.DOM.find(button, 'span', 'global-spaces-dropdown-icon');
    JX.DOM.alterClass(icon, data.icon, false);
    data.icon = new_icon;
    JX.DOM.alterClass(icon, data.icon, true);
  }

  function updateText(button, data, new_text) {
    var text = JX.DOM.find(button, 'span', 'global-spaces-dropdown-text');
    text.innerHTML = new_text;
  }

  // Implement the scope selector menu for the global search.
  JX.Stratcom.listen('click', 'global-spaces-dropdown', function(e) {
    var data = e.getNodeData('global-spaces-dropdown');
    var button = e.getNode('global-spaces-dropdown');
    if (data.menu) {
      return;
    }

    e.kill();

    function updateValue(spec) {
      if (data.value == spec.value) {
        return;
      }

      // Swap out the icon.
      updateIcon(button, data, spec.icon);

      // Swap out the text.
      updateText(button, data, spec.name);

      // Update the value.
      data.value = spec.value;

      new JX.Request(config.scopeUpdateURI)
        .setData({value: data.value})
        .send();

      var spaceSelectControlKnobs = document.getElementsByClassName('aphront-space-select-control-knob');
      for (var ii = 0; ii < spaceSelectControlKnobs.length; ii++) {
        spaceSelectControlKnobs[ii].value = spec.value;
      }
    }

    var menu = new JX.PHUIXDropdownMenu(button)
      .setAlign('left');
    data.menu = menu;

    menu.listen('open', function() {
      var list = new JX.PHUIXActionListView();

      for (var ii = 0; ii < data.items.length; ii++) {
        var spec = data.items[ii];

        var item = new JX.PHUIXActionView()
          .setName(spec.name)
          .setIcon(spec.icon);

        if (spec.value) {
          if (spec.value == data.value) {
            item.setSelected(true);
          }

          var handler = function(spec, e) {
            e.prevent();
            menu.close();
            updateValue(spec);
          };

          item.setHandler(JX.bind(null, handler, spec));
        } else if (spec.href) {
          item.setHref(spec.href);
          item.setHandler(function() { menu.close(); });
        } else {
          item.setLabel(true);
        }

        list.addItem(item);
      }

      menu.setContent(list.getNode());
    });

    menu.open();
  });


});

src/view/page/menu/PhabricatorMainMenuSpacesView.php:

<?php

final class PhabricatorMainMenuSpacesView extends AphrontView {

  const DEFAULT_APPLICATION_ICON = 'fa-dot-circle-o';

  private $id;
  private $application;

  public function setApplication(PhabricatorApplication $application) {
    $this->application = $application;
    return $this;
  }

  public function getApplication() {
    return $this->application;
  }

  public function getID() {
    if (!$this->id) {
      $this->id = celerity_generate_unique_node_id();
    }
    return $this->id;
  }

  public function render() {
    $user = $this->user;

    $target_id = celerity_generate_unique_node_id();
    $search_id = $this->getID();
    $button_id = celerity_generate_unique_node_id();
    $selector_id = celerity_generate_unique_node_id();

    $current_space_key = PhabricatorUserPreferences::PREFERENCE_CURRENT_SPACE;

    Javelin::initBehavior(
      'phabricator-spaces-switcher',
      array(
        'id' => $target_id,
        'input' => $search_id,
        'button' => $button_id,
        'selectorID' => $selector_id,
        'defaultApplicationIcon' => self::DEFAULT_APPLICATION_ICON,
        'scopeUpdateURI' => '/settings/adjust/?key='.$current_space_key,
      ));

    $selector = $this->buildModeSelector($selector_id);

    $tag = phutil_tag_div('phabricator-main-menu-search-container', array(
        $selector));

    return $tag;
  }

  private function buildModeSelector($selector_id) {
    $viewer = $this->getUser();

    $items = array();
    $items[] = array(
      'name' => pht('Spaces'),
    );

    $spaces = PhabricatorSpacesNamespaceQuery::getViewerActiveSpaces($viewer);
    foreach ($spaces as $space) {
      $items[] = array(
        'icon' => 'fa-certificate',
        'name' => pht("%s: %s",
          $space->getMonogram(),
          $space->getNamespaceName()),
        'value' => $space->getPHID(),
      );
    }

    $items[] =  array(
      'name' => pht('More Options'),
    );

    $items[] = array(
      'icon' => 'fa-book',
      'name' => pht('User Guide: Spaces'),
      'href' => PhabricatorEnv::getDoclink('Spaces User Guide'),
    );

    $current_space_key = PhabricatorUserPreferences::PREFERENCE_CURRENT_SPACE;
    $current_value = $viewer->loadPreferences()->getPreference(
      $current_space_key,
      $viewer->getDefaultSpacePHID());

    $current_icon = 'fa-globe';
    foreach ($items as $item) {
      if (idx($item, 'value') == $current_value) {
        $current_icon = $item['icon'];
        break;
      }
    }

    $current_text = 'Unknown';
    foreach ($items as $item) {
      if (idx($item, 'value') == $current_value) {
        $current_text = $item['name'];
        break;
      }
    }

    $selector = id(new PHUIButtonView())
      ->setID($selector_id)
      ->addClass('phabricator-main-menu-spaces-dropdown')
      ->addSigil('global-spaces-dropdown')
      ->setMetadata(
        array(
          'items' => $items,
          'icon' => $current_icon,
          'text' => $current_text,
        ))
      ->setIcon(
        id(new PHUIIconView())
          ->addSigil('global-spaces-dropdown-icon')
          ->setIconFont($current_icon))
      ->setText(
        id(new PHUITextView())
          ->addSigil('global-spaces-dropdown-text')
          ->setText($current_text))
      ->setDropdown(true);

    return $selector;
  }

}

Updated to fix a bug where the default $space_phid (and $current_value) would be 'all' instead of $actor->getDefaultSpacePHID().