mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-25 16:22:43 +01:00
Allow users to customize applicaiton tile sizes
Summary: See discussion in D4438. Allows users to customize application tiles, and implements generally reasonable defaults so they hopefully won't. Sizes are "invisible" (internal only, used to hide admin apps from non-admins), "hidden" (hide by default, show after clicking "Show More Applications"), "show" (show a small square tile) and "full" (show a full-width tile with subtitle). Test Plan: Default view for a non-admin: {F29375} Adjusted settings, hidden: {F29373} Adjusted settings, shown: {F29374} Reviewers: chad, btrahan Reviewed By: chad CC: aran Differential Revision: https://secure.phabricator.com/D4439
This commit is contained in:
parent
fb9a1c38fb
commit
fffa7ffb6c
8 changed files with 335 additions and 42 deletions
|
@ -57,6 +57,7 @@ $package_spec = array(
|
|||
'phabricator-textareautils',
|
||||
'phabricator-file-upload',
|
||||
'javelin-behavior-global-drag-and-drop',
|
||||
'javelin-behavior-phabricator-home-reveal-tiles',
|
||||
),
|
||||
'core.pkg.css' => array(
|
||||
'phabricator-core-css',
|
||||
|
|
|
@ -1185,6 +1185,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorSettingsPanelDisplayPreferences' => 'applications/settings/panel/PhabricatorSettingsPanelDisplayPreferences.php',
|
||||
'PhabricatorSettingsPanelEmailAddresses' => 'applications/settings/panel/PhabricatorSettingsPanelEmailAddresses.php',
|
||||
'PhabricatorSettingsPanelEmailPreferences' => 'applications/settings/panel/PhabricatorSettingsPanelEmailPreferences.php',
|
||||
'PhabricatorSettingsPanelHomePreferences' => 'applications/settings/panel/PhabricatorSettingsPanelHomePreferences.php',
|
||||
'PhabricatorSettingsPanelLDAP' => 'applications/settings/panel/PhabricatorSettingsPanelLDAP.php',
|
||||
'PhabricatorSettingsPanelOAuth' => 'applications/settings/panel/PhabricatorSettingsPanelOAuth.php',
|
||||
'PhabricatorSettingsPanelPassword' => 'applications/settings/panel/PhabricatorSettingsPanelPassword.php',
|
||||
|
@ -2525,6 +2526,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorSettingsPanelDisplayPreferences' => 'PhabricatorSettingsPanel',
|
||||
'PhabricatorSettingsPanelEmailAddresses' => 'PhabricatorSettingsPanel',
|
||||
'PhabricatorSettingsPanelEmailPreferences' => 'PhabricatorSettingsPanel',
|
||||
'PhabricatorSettingsPanelHomePreferences' => 'PhabricatorSettingsPanel',
|
||||
'PhabricatorSettingsPanelLDAP' => 'PhabricatorSettingsPanel',
|
||||
'PhabricatorSettingsPanelOAuth' => 'PhabricatorSettingsPanel',
|
||||
'PhabricatorSettingsPanelPassword' => 'PhabricatorSettingsPanel',
|
||||
|
|
|
@ -18,6 +18,11 @@ abstract class PhabricatorApplication {
|
|||
const GROUP_DEVELOPER = 'developer';
|
||||
const GROUP_MISC = 'misc';
|
||||
|
||||
const TILE_INVISIBLE = 'invisible';
|
||||
const TILE_HIDE = 'hide';
|
||||
const TILE_SHOW = 'show';
|
||||
const TILE_FULL = 'full';
|
||||
|
||||
public static function getApplicationGroups() {
|
||||
return array(
|
||||
self::GROUP_CORE => pht('Core Applications'),
|
||||
|
@ -30,6 +35,17 @@ abstract class PhabricatorApplication {
|
|||
);
|
||||
}
|
||||
|
||||
public static function getTileDisplayName($constant) {
|
||||
$names = array(
|
||||
self::TILE_INVISIBLE => pht('Invisible'),
|
||||
self::TILE_HIDE => pht('Hidden'),
|
||||
self::TILE_SHOW => pht('Show Small Tile'),
|
||||
self::TILE_FULL => pht('Show Large Tile'),
|
||||
);
|
||||
return idx($names, $constant);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* -( Application Information )-------------------------------------------- */
|
||||
|
||||
|
@ -96,6 +112,25 @@ abstract class PhabricatorApplication {
|
|||
return array();
|
||||
}
|
||||
|
||||
public function getDefaultTileDisplay(PhabricatorUser $user) {
|
||||
switch ($this->getApplicationGroup()) {
|
||||
case self::GROUP_CORE:
|
||||
return self::TILE_FULL;
|
||||
case self::GROUP_UTILITIES:
|
||||
case self::GROUP_DEVELOPER:
|
||||
return self::TILE_HIDE;
|
||||
case self::GROUP_ADMIN:
|
||||
if ($user->getIsAdmin()) {
|
||||
return self::TILE_SHOW;
|
||||
} else {
|
||||
return self::TILE_INVISIBLE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return self::TILE_SHOW;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* -( URI Routing )-------------------------------------------------------- */
|
||||
|
||||
|
|
|
@ -25,51 +25,129 @@ abstract class PhabricatorDirectoryController extends PhabricatorController {
|
|||
|
||||
foreach ($applications as $key => $application) {
|
||||
if (!$application->shouldAppearInLaunchView()) {
|
||||
// Remove hidden applications (usually internal stuff).
|
||||
unset($applications[$key]);
|
||||
}
|
||||
$invisible = PhabricatorApplication::TILE_INVISIBLE;
|
||||
if ($application->getDefaultTileDisplay($user) == $invisible) {
|
||||
// Remove invisible applications (e.g., admin apps for non-admins).
|
||||
unset($applications[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
$groups = PhabricatorApplication::getApplicationGroups();
|
||||
|
||||
$applications = msort($applications, 'getApplicationOrder');
|
||||
$applications = mgroup($applications, 'getApplicationGroup');
|
||||
$applications = array_select_keys($applications, array_keys($groups));
|
||||
|
||||
$view = array();
|
||||
foreach ($applications as $group => $application_list) {
|
||||
$status = array();
|
||||
foreach ($application_list as $key => $application) {
|
||||
$status[$key] = $application->loadStatus($user);
|
||||
}
|
||||
|
||||
$views = array();
|
||||
foreach ($application_list as $key => $application) {
|
||||
$tile = id(new PhabricatorApplicationLaunchView())
|
||||
->setApplication($application)
|
||||
->setApplicationStatus(idx($status, $key, array()))
|
||||
->setUser($user);
|
||||
|
||||
if ($group == PhabricatorApplication::GROUP_CORE) {
|
||||
$tile->setFullWidth(true);
|
||||
}
|
||||
|
||||
$views[] = $tile;
|
||||
}
|
||||
|
||||
while (count($views) % 4) {
|
||||
$views[] = id(new PhabricatorApplicationLaunchView());
|
||||
}
|
||||
|
||||
$nav->addLabel($groups[$group]);
|
||||
$nav->addCustomBlock(
|
||||
phutil_render_tag(
|
||||
'div',
|
||||
array(
|
||||
'class' => 'application-tile-group',
|
||||
),
|
||||
id(new AphrontNullView())->appendChild($views)->render()));
|
||||
$status = array();
|
||||
foreach ($applications as $key => $application) {
|
||||
$status[get_class($application)] = $application->loadStatus($user);
|
||||
}
|
||||
|
||||
$tile_groups = array();
|
||||
$prefs = $user->loadPreferences()->getPreference(
|
||||
PhabricatorUserPreferences::PREFERENCE_APP_TILES,
|
||||
array());
|
||||
foreach ($applications as $key => $application) {
|
||||
$display = idx(
|
||||
$prefs,
|
||||
get_class($application),
|
||||
$application->getDefaultTileDisplay($user));
|
||||
$tile_groups[$display][] = $application;
|
||||
}
|
||||
|
||||
$tile_groups = array_select_keys(
|
||||
$tile_groups,
|
||||
array(
|
||||
PhabricatorApplication::TILE_FULL,
|
||||
PhabricatorApplication::TILE_SHOW,
|
||||
PhabricatorApplication::TILE_HIDE,
|
||||
));
|
||||
|
||||
foreach ($tile_groups as $tile_display => $tile_group) {
|
||||
if (!$tile_group) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$tile_group = msort($tile_group, 'getApplicationOrder');
|
||||
|
||||
$is_small_tiles = ($tile_display == PhabricatorApplication::TILE_SHOW) ||
|
||||
($tile_display == PhabricatorApplication::TILE_HIDE);
|
||||
|
||||
if ($is_small_tiles) {
|
||||
$groups = PhabricatorApplication::getApplicationGroups();
|
||||
$tile_group = mgroup($tile_group, 'getApplicationGroup');
|
||||
$tile_group = array_select_keys($tile_group, array_keys($groups));
|
||||
} else {
|
||||
$tile_group = array($tile_group);
|
||||
}
|
||||
|
||||
$is_hide = ($tile_display == PhabricatorApplication::TILE_HIDE);
|
||||
if ($is_hide) {
|
||||
$show_item_id = celerity_generate_unique_node_id();
|
||||
$show_tiles_id = celerity_generate_unique_node_id();
|
||||
|
||||
$show_item = id(new PhabricatorMenuItemView())
|
||||
->setName(pht('Show More Applications'))
|
||||
->setHref('#')
|
||||
->addSigil('home-show-applications')
|
||||
->setID($show_item_id);
|
||||
|
||||
$hide_item = id(new PhabricatorMenuItemView())
|
||||
->setName(pht('Show Fewer Applications'))
|
||||
->setHref('#')
|
||||
->addSigil('home-hide-applications');
|
||||
|
||||
$nav->addMenuItem($show_item);
|
||||
$nav->addCustomBlock(
|
||||
'<div '.
|
||||
'id="'.phutil_escape_html($show_tiles_id).'"'.
|
||||
'style="display: none;">');
|
||||
|
||||
Javelin::initBehavior('phabricator-home-reveal-tiles', array(
|
||||
'tilesID' => $show_tiles_id,
|
||||
'showID' => $show_item_id,
|
||||
));
|
||||
}
|
||||
|
||||
foreach ($tile_group as $group => $application_list) {
|
||||
$tiles = array();
|
||||
foreach ($application_list as $key => $application) {
|
||||
$tile = id(new PhabricatorApplicationLaunchView())
|
||||
->setApplication($application)
|
||||
->setApplicationStatus(
|
||||
idx($status, get_class($application), array()))
|
||||
->setUser($user);
|
||||
|
||||
if ($tile_display == PhabricatorApplication::TILE_FULL) {
|
||||
$tile->setFullWidth(true);
|
||||
}
|
||||
|
||||
$tiles[] = $tile;
|
||||
}
|
||||
|
||||
if ($is_small_tiles) {
|
||||
while (count($tiles) % 4) {
|
||||
$tiles[] = id(new PhabricatorApplicationLaunchView());
|
||||
}
|
||||
$nav->addLabel($groups[$group]);
|
||||
}
|
||||
$nav->addCustomBlock(
|
||||
phutil_render_tag(
|
||||
'div',
|
||||
array(
|
||||
'class' => 'application-tile-group',
|
||||
),
|
||||
id(new AphrontNullView())->appendChild($tiles)->render()));
|
||||
}
|
||||
|
||||
$is_hide = ($tile_display == PhabricatorApplication::TILE_HIDE);
|
||||
if ($is_hide) {
|
||||
$nav->addMenuItem($hide_item);
|
||||
$nav->addCustomBlock('</div>');
|
||||
}
|
||||
}
|
||||
|
||||
$nav->addFilter(
|
||||
'',
|
||||
pht('Customize Applications...'),
|
||||
'/settings/panel/home/');
|
||||
$nav->addClass('phabricator-side-menu-home');
|
||||
$nav->selectFilter(null);
|
||||
|
||||
|
|
|
@ -0,0 +1,108 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorSettingsPanelHomePreferences
|
||||
extends PhabricatorSettingsPanel {
|
||||
|
||||
public function getPanelKey() {
|
||||
return 'home';
|
||||
}
|
||||
|
||||
public function getPanelName() {
|
||||
return pht('Home Page');
|
||||
}
|
||||
|
||||
public function getPanelGroup() {
|
||||
return pht('Application Settings');
|
||||
}
|
||||
|
||||
public function processRequest(AphrontRequest $request) {
|
||||
$user = $request->getUser();
|
||||
$preferences = $user->loadPreferences();
|
||||
|
||||
$apps = PhabricatorApplication::getAllInstalledApplications();
|
||||
$pref_tiles = PhabricatorUserPreferences::PREFERENCE_APP_TILES;
|
||||
$tiles = $preferences->getPreference($pref_tiles, array());
|
||||
|
||||
if ($request->isFormPost()) {
|
||||
$values = $request->getArr('tile');
|
||||
foreach ($apps as $app) {
|
||||
$key = get_class($app);
|
||||
$value = idx($values, $key);
|
||||
switch ($value) {
|
||||
case PhabricatorApplication::TILE_FULL:
|
||||
case PhabricatorApplication::TILE_SHOW:
|
||||
case PhabricatorApplication::TILE_HIDE:
|
||||
$tiles[$key] = $value;
|
||||
break;
|
||||
default:
|
||||
unset($tiles[$key]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
$preferences->setPreference($pref_tiles, $tiles);
|
||||
$preferences->save();
|
||||
|
||||
return id(new AphrontRedirectResponse())
|
||||
->setURI($this->getPanelURI('?saved=true'));
|
||||
}
|
||||
|
||||
$header = id(new PhabricatorHeaderView())
|
||||
->setHeader(pht('Home Page Preferences'));
|
||||
|
||||
$form = id(new AphrontFormView())
|
||||
->setFlexible(true)
|
||||
->setUser($user);
|
||||
|
||||
$apps = msort($apps, 'getName');
|
||||
foreach ($apps as $app) {
|
||||
if (!$app->shouldAppearInLaunchView()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$default = $app->getDefaultTileDisplay($user);
|
||||
if ($default == PhabricatorApplication::TILE_INVISIBLE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$default_name = PhabricatorApplication::getTileDisplayName($default);
|
||||
|
||||
$hide = PhabricatorApplication::TILE_HIDE;
|
||||
$show = PhabricatorApplication::TILE_SHOW;
|
||||
$full = PhabricatorApplication::TILE_FULL;
|
||||
|
||||
$key = get_class($app);
|
||||
$form->appendChild(
|
||||
id(new AphrontFormSelectControl())
|
||||
->setLabel($app->getName())
|
||||
->setName('tile['.$key.']')
|
||||
->setOptions(
|
||||
array(
|
||||
$hide => PhabricatorApplication::getTileDisplayName($hide),
|
||||
'default' => pht('Use Default (%s)', $default_name),
|
||||
$show => PhabricatorApplication::getTileDisplayName($show),
|
||||
$full => PhabricatorApplication::getTileDisplayName($full),
|
||||
))
|
||||
->setValue(idx($tiles, $key, 'default')));
|
||||
}
|
||||
|
||||
$form
|
||||
->appendChild(
|
||||
id(new AphrontFormSubmitControl())
|
||||
->setValue('Save Preferences'));
|
||||
|
||||
$error_view = null;
|
||||
if ($request->getStr('saved') === 'true') {
|
||||
$error_view = id(new AphrontErrorView())
|
||||
->setTitle('Preferences Saved')
|
||||
->setSeverity(AphrontErrorView::SEVERITY_NOTICE)
|
||||
->setErrors(array('Your preferences have been saved.'));
|
||||
}
|
||||
|
||||
return array(
|
||||
$header,
|
||||
$error_view,
|
||||
$form,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -20,6 +20,7 @@ final class PhabricatorUserPreferences extends PhabricatorUserDAO {
|
|||
const PREFERENCE_DIFFUSION_SYMBOLS = 'diffusion-symbols';
|
||||
|
||||
const PREFERENCE_NAV_WIDTH = 'nav-width';
|
||||
const PREFERENCE_APP_TILES = 'app-tiles';
|
||||
|
||||
protected $userPHID;
|
||||
protected $preferences = array();
|
||||
|
|
|
@ -16,6 +16,33 @@ final class PhabricatorMenuItemView extends AphrontView {
|
|||
private $sortOrder = 1.0;
|
||||
private $icon;
|
||||
private $selected;
|
||||
private $sigils = array();
|
||||
private $metadata;
|
||||
private $id;
|
||||
|
||||
public function setID($id) {
|
||||
$this->id = $id;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setProperty($property) {
|
||||
$this->property = $property;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getProperty() {
|
||||
return $this->property;
|
||||
}
|
||||
|
||||
public function setMetadata($metadata) {
|
||||
$this->metadata = $metadata;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function addSigil($sigil) {
|
||||
$this->sigils[] = $sigil;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setSelected($selected) {
|
||||
$this->selected = $selected;
|
||||
|
@ -125,12 +152,24 @@ final class PhabricatorMenuItemView extends AphrontView {
|
|||
phutil_escape_html($this->name.$external));
|
||||
}
|
||||
|
||||
$sigils = $this->sigils;
|
||||
if ($this->workflow) {
|
||||
$sigils[] = 'workflow';
|
||||
}
|
||||
if ($sigils) {
|
||||
$sigils = implode(' ', $sigils);
|
||||
} else {
|
||||
$sigils = null;
|
||||
}
|
||||
|
||||
return javelin_render_tag(
|
||||
$this->href ? 'a' : 'div',
|
||||
array(
|
||||
'class' => implode(' ', $classes),
|
||||
'href' => $this->href,
|
||||
'sigil' => $this->workflow ? 'workflow' : null,
|
||||
'class' => implode(' ', $classes),
|
||||
'href' => $this->href,
|
||||
'sigil' => $sigils,
|
||||
'meta' => $this->metadata,
|
||||
'id' => $this->id,
|
||||
),
|
||||
$this->renderChildren().
|
||||
$name);
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
/**
|
||||
* @provides javelin-behavior-phabricator-home-reveal-tiles
|
||||
* @requires javelin-behavior
|
||||
* javelin-stratcom
|
||||
* javelin-dom
|
||||
* @javelin
|
||||
*/
|
||||
|
||||
JX.behavior('phabricator-home-reveal-tiles', function(config) {
|
||||
JX.Stratcom.listen(
|
||||
'click',
|
||||
'home-show-applications',
|
||||
function(e) {
|
||||
e.kill();
|
||||
|
||||
JX.DOM.show(JX.$(config.tilesID));
|
||||
JX.DOM.hide(JX.$(config.showID));
|
||||
});
|
||||
|
||||
JX.Stratcom.listen(
|
||||
'click',
|
||||
'home-hide-applications',
|
||||
function(e) {
|
||||
e.kill();
|
||||
|
||||
JX.DOM.hide(JX.$(config.tilesID));
|
||||
JX.DOM.show(JX.$(config.showID));
|
||||
});
|
||||
});
|
Loading…
Reference in a new issue