mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-03 20:22:46 +01:00
(stable) Promote 2017 Week 5
This commit is contained in:
commit
43fae71e17
113 changed files with 2419 additions and 1917 deletions
22
externals/recaptcha/LICENSE
vendored
22
externals/recaptcha/LICENSE
vendored
|
@ -1,22 +0,0 @@
|
|||
Copyright (c) 2007 reCAPTCHA -- http://recaptcha.net
|
||||
AUTHORS:
|
||||
Mike Crawford
|
||||
Ben Maurer
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
277
externals/recaptcha/recaptchalib.php
vendored
277
externals/recaptcha/recaptchalib.php
vendored
|
@ -1,277 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
* This is a PHP library that handles calling reCAPTCHA.
|
||||
* - Documentation and latest version
|
||||
* http://recaptcha.net/plugins/php/
|
||||
* - Get a reCAPTCHA API Key
|
||||
* https://www.google.com/recaptcha/admin/create
|
||||
* - Discussion group
|
||||
* http://groups.google.com/group/recaptcha
|
||||
*
|
||||
* Copyright (c) 2007 reCAPTCHA -- http://recaptcha.net
|
||||
* AUTHORS:
|
||||
* Mike Crawford
|
||||
* Ben Maurer
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The reCAPTCHA server URL's
|
||||
*/
|
||||
define("RECAPTCHA_API_SERVER", "http://www.google.com/recaptcha/api");
|
||||
define("RECAPTCHA_API_SECURE_SERVER", "https://www.google.com/recaptcha/api");
|
||||
define("RECAPTCHA_VERIFY_SERVER", "www.google.com");
|
||||
|
||||
/**
|
||||
* Encodes the given data into a query string format
|
||||
* @param $data - array of string elements to be encoded
|
||||
* @return string - encoded request
|
||||
*/
|
||||
function _recaptcha_qsencode ($data) {
|
||||
$req = "";
|
||||
foreach ( $data as $key => $value )
|
||||
$req .= $key . '=' . urlencode( stripslashes($value) ) . '&';
|
||||
|
||||
// Cut the last '&'
|
||||
$req=substr($req,0,strlen($req)-1);
|
||||
return $req;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Submits an HTTP POST to a reCAPTCHA server
|
||||
* @param string $host
|
||||
* @param string $path
|
||||
* @param array $data
|
||||
* @param int port
|
||||
* @return array response
|
||||
*/
|
||||
function _recaptcha_http_post($host, $path, $data, $port = 80) {
|
||||
|
||||
$req = _recaptcha_qsencode ($data);
|
||||
|
||||
$http_request = "POST $path HTTP/1.0\r\n";
|
||||
$http_request .= "Host: $host\r\n";
|
||||
$http_request .= "Content-Type: application/x-www-form-urlencoded;\r\n";
|
||||
$http_request .= "Content-Length: " . strlen($req) . "\r\n";
|
||||
$http_request .= "User-Agent: reCAPTCHA/PHP\r\n";
|
||||
$http_request .= "\r\n";
|
||||
$http_request .= $req;
|
||||
|
||||
$response = '';
|
||||
if( false == ( $fs = @fsockopen($host, $port, $errno, $errstr, 10) ) ) {
|
||||
die ('Could not open socket');
|
||||
}
|
||||
|
||||
fwrite($fs, $http_request);
|
||||
|
||||
while ( !feof($fs) )
|
||||
$response .= fgets($fs, 1160); // One TCP-IP packet
|
||||
fclose($fs);
|
||||
$response = explode("\r\n\r\n", $response, 2);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Gets the challenge HTML (javascript and non-javascript version).
|
||||
* This is called from the browser, and the resulting reCAPTCHA HTML widget
|
||||
* is embedded within the HTML form it was called from.
|
||||
* @param string $pubkey A public key for reCAPTCHA
|
||||
* @param string $error The error given by reCAPTCHA (optional, default is null)
|
||||
* @param boolean $use_ssl Should the request be made over ssl? (optional, default is false)
|
||||
|
||||
* @return string - The HTML to be embedded in the user's form.
|
||||
*/
|
||||
function recaptcha_get_html ($pubkey, $error = null, $use_ssl = false)
|
||||
{
|
||||
if ($pubkey == null || $pubkey == '') {
|
||||
die ("To use reCAPTCHA you must get an API key from <a href='https://www.google.com/recaptcha/admin/create'>https://www.google.com/recaptcha/admin/create</a>");
|
||||
}
|
||||
|
||||
if ($use_ssl) {
|
||||
$server = RECAPTCHA_API_SECURE_SERVER;
|
||||
} else {
|
||||
$server = RECAPTCHA_API_SERVER;
|
||||
}
|
||||
|
||||
$errorpart = "";
|
||||
if ($error) {
|
||||
$errorpart = "&error=" . $error;
|
||||
}
|
||||
return '<script type="text/javascript" src="'. $server . '/challenge?k=' . $pubkey . $errorpart . '"></script>
|
||||
|
||||
<noscript>
|
||||
<iframe src="'. $server . '/noscript?k=' . $pubkey . $errorpart . '" height="300" width="500" frameborder="0"></iframe><br/>
|
||||
<textarea name="recaptcha_challenge_field" rows="3" cols="40"></textarea>
|
||||
<input type="hidden" name="recaptcha_response_field" value="manual_challenge"/>
|
||||
</noscript>';
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A ReCaptchaResponse is returned from recaptcha_check_answer()
|
||||
*/
|
||||
class ReCaptchaResponse {
|
||||
var $is_valid;
|
||||
var $error;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calls an HTTP POST function to verify if the user's guess was correct
|
||||
* @param string $privkey
|
||||
* @param string $remoteip
|
||||
* @param string $challenge
|
||||
* @param string $response
|
||||
* @param array $extra_params an array of extra variables to post to the server
|
||||
* @return ReCaptchaResponse
|
||||
*/
|
||||
function recaptcha_check_answer ($privkey, $remoteip, $challenge, $response, $extra_params = array())
|
||||
{
|
||||
if ($privkey == null || $privkey == '') {
|
||||
die ("To use reCAPTCHA you must get an API key from <a href='https://www.google.com/recaptcha/admin/create'>https://www.google.com/recaptcha/admin/create</a>");
|
||||
}
|
||||
|
||||
if ($remoteip == null || $remoteip == '') {
|
||||
die ("For security reasons, you must pass the remote ip to reCAPTCHA");
|
||||
}
|
||||
|
||||
|
||||
|
||||
//discard spam submissions
|
||||
if ($challenge == null || strlen($challenge) == 0 || $response == null || strlen($response) == 0) {
|
||||
$recaptcha_response = new ReCaptchaResponse();
|
||||
$recaptcha_response->is_valid = false;
|
||||
$recaptcha_response->error = 'incorrect-captcha-sol';
|
||||
return $recaptcha_response;
|
||||
}
|
||||
|
||||
$response = _recaptcha_http_post (RECAPTCHA_VERIFY_SERVER, "/recaptcha/api/verify",
|
||||
array (
|
||||
'privatekey' => $privkey,
|
||||
'remoteip' => $remoteip,
|
||||
'challenge' => $challenge,
|
||||
'response' => $response
|
||||
) + $extra_params
|
||||
);
|
||||
|
||||
$answers = explode ("\n", $response [1]);
|
||||
$recaptcha_response = new ReCaptchaResponse();
|
||||
|
||||
if (trim ($answers [0]) == 'true') {
|
||||
$recaptcha_response->is_valid = true;
|
||||
}
|
||||
else {
|
||||
$recaptcha_response->is_valid = false;
|
||||
$recaptcha_response->error = $answers [1];
|
||||
}
|
||||
return $recaptcha_response;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* gets a URL where the user can sign up for reCAPTCHA. If your application
|
||||
* has a configuration page where you enter a key, you should provide a link
|
||||
* using this function.
|
||||
* @param string $domain The domain where the page is hosted
|
||||
* @param string $appname The name of your application
|
||||
*/
|
||||
function recaptcha_get_signup_url ($domain = null, $appname = null) {
|
||||
return "https://www.google.com/recaptcha/admin/create?" . _recaptcha_qsencode (array ('domains' => $domain, 'app' => $appname));
|
||||
}
|
||||
|
||||
function _recaptcha_aes_pad($val) {
|
||||
$block_size = 16;
|
||||
$numpad = $block_size - (strlen ($val) % $block_size);
|
||||
return str_pad($val, strlen ($val) + $numpad, chr($numpad));
|
||||
}
|
||||
|
||||
/* Mailhide related code */
|
||||
|
||||
function _recaptcha_aes_encrypt($val,$ky) {
|
||||
if (! function_exists ("mcrypt_encrypt")) {
|
||||
die ("To use reCAPTCHA Mailhide, you need to have the mcrypt php module installed.");
|
||||
}
|
||||
$mode=MCRYPT_MODE_CBC;
|
||||
$enc=MCRYPT_RIJNDAEL_128;
|
||||
$val=_recaptcha_aes_pad($val);
|
||||
return mcrypt_encrypt($enc, $ky, $val, $mode, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
|
||||
}
|
||||
|
||||
|
||||
function _recaptcha_mailhide_urlbase64 ($x) {
|
||||
return strtr(base64_encode ($x), '+/', '-_');
|
||||
}
|
||||
|
||||
/* gets the reCAPTCHA Mailhide url for a given email, public key and private key */
|
||||
function recaptcha_mailhide_url($pubkey, $privkey, $email) {
|
||||
if ($pubkey == '' || $pubkey == null || $privkey == "" || $privkey == null) {
|
||||
die ("To use reCAPTCHA Mailhide, you have to sign up for a public and private key, " .
|
||||
"you can do so at <a href='http://www.google.com/recaptcha/mailhide/apikey'>http://www.google.com/recaptcha/mailhide/apikey</a>");
|
||||
}
|
||||
|
||||
|
||||
$ky = pack('H*', $privkey);
|
||||
$cryptmail = _recaptcha_aes_encrypt ($email, $ky);
|
||||
|
||||
return "http://www.google.com/recaptcha/mailhide/d?k=" . $pubkey . "&c=" . _recaptcha_mailhide_urlbase64 ($cryptmail);
|
||||
}
|
||||
|
||||
/**
|
||||
* gets the parts of the email to expose to the user.
|
||||
* eg, given johndoe@example,com return ["john", "example.com"].
|
||||
* the email is then displayed as john...@example.com
|
||||
*/
|
||||
function _recaptcha_mailhide_email_parts ($email) {
|
||||
$arr = preg_split("/@/", $email );
|
||||
|
||||
if (strlen ($arr[0]) <= 4) {
|
||||
$arr[0] = substr ($arr[0], 0, 1);
|
||||
} else if (strlen ($arr[0]) <= 6) {
|
||||
$arr[0] = substr ($arr[0], 0, 3);
|
||||
} else {
|
||||
$arr[0] = substr ($arr[0], 0, 4);
|
||||
}
|
||||
return $arr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets html to display an email address given a public an private key.
|
||||
* to get a key, go to:
|
||||
*
|
||||
* http://www.google.com/recaptcha/mailhide/apikey
|
||||
*/
|
||||
function recaptcha_mailhide_html($pubkey, $privkey, $email) {
|
||||
$emailparts = _recaptcha_mailhide_email_parts ($email);
|
||||
$url = recaptcha_mailhide_url ($pubkey, $privkey, $email);
|
||||
|
||||
return htmlentities($emailparts[0]) . "<a href='" . htmlentities ($url) .
|
||||
"' onclick=\"window.open('" . htmlentities ($url) . "', '', 'toolbar=0,scrollbars=0,location=0,statusbar=0,menubar=0,resizable=0,width=500,height=300'); return false;\" title=\"Reveal this e-mail address\">...</a>@" . htmlentities ($emailparts [1]);
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
|
@ -9,8 +9,8 @@ return array(
|
|||
'names' => array(
|
||||
'conpherence.pkg.css' => 'e25569a9',
|
||||
'conpherence.pkg.js' => '6249a1cf',
|
||||
'core.pkg.css' => 'ea0e9c0c',
|
||||
'core.pkg.js' => '2291d3b2',
|
||||
'core.pkg.css' => '867a3ad4',
|
||||
'core.pkg.js' => '1fa7c0c5',
|
||||
'darkconsole.pkg.js' => 'e7393ebb',
|
||||
'differential.pkg.css' => '4815647b',
|
||||
'differential.pkg.js' => 'ddfeb49b',
|
||||
|
@ -27,17 +27,16 @@ return array(
|
|||
'rsrc/css/aphront/notification.css' => '3f6c89c9',
|
||||
'rsrc/css/aphront/panel-view.css' => '8427b78d',
|
||||
'rsrc/css/aphront/phabricator-nav-view.css' => 'b29426e9',
|
||||
'rsrc/css/aphront/table-view.css' => '3225137a',
|
||||
'rsrc/css/aphront/table-view.css' => '213a5981',
|
||||
'rsrc/css/aphront/tokenizer.css' => '9a8cb501',
|
||||
'rsrc/css/aphront/tooltip.css' => '1a07aea8',
|
||||
'rsrc/css/aphront/tooltip.css' => '173b9431',
|
||||
'rsrc/css/aphront/typeahead-browse.css' => '8904346a',
|
||||
'rsrc/css/aphront/typeahead.css' => 'd4f16145',
|
||||
'rsrc/css/application/almanac/almanac.css' => 'dbb9b3af',
|
||||
'rsrc/css/application/auth/auth.css' => '0877ed6e',
|
||||
'rsrc/css/application/base/main-menu-view.css' => '8eac4166',
|
||||
'rsrc/css/application/base/main-menu-view.css' => '62c04564',
|
||||
'rsrc/css/application/base/notification-menu.css' => '6a697e43',
|
||||
'rsrc/css/application/base/phabricator-application-launch-view.css' => '95351601',
|
||||
'rsrc/css/application/base/phui-theme.css' => '798c69b8',
|
||||
'rsrc/css/application/base/phui-theme.css' => '9f261c6b',
|
||||
'rsrc/css/application/base/standard-page-view.css' => '894d8a25',
|
||||
'rsrc/css/application/chatlog/chatlog.css' => 'd295b020',
|
||||
'rsrc/css/application/conduit/conduit-api.css' => '7bc725c4',
|
||||
|
@ -68,7 +67,7 @@ return array(
|
|||
'rsrc/css/application/differential/table-of-contents.css' => 'ae4b7a55',
|
||||
'rsrc/css/application/diffusion/diffusion-icons.css' => 'd678600a',
|
||||
'rsrc/css/application/diffusion/diffusion-readme.css' => '297373eb',
|
||||
'rsrc/css/application/diffusion/diffusion-source.css' => '68b30fd3',
|
||||
'rsrc/css/application/diffusion/diffusion-source.css' => '750add59',
|
||||
'rsrc/css/application/feed/feed.css' => 'ecd4ec57',
|
||||
'rsrc/css/application/files/global-drag-and-drop.css' => '5c1b47c2',
|
||||
'rsrc/css/application/flag/flag.css' => 'bba8f811',
|
||||
|
@ -82,6 +81,7 @@ return array(
|
|||
'rsrc/css/application/objectselector/object-selector.css' => '85ee8ce6',
|
||||
'rsrc/css/application/owners/owners-path-editor.css' => '2f00933b',
|
||||
'rsrc/css/application/paste/paste.css' => '1898e534',
|
||||
'rsrc/css/application/people/people-picture-menu-item.css' => '1ac65ef7',
|
||||
'rsrc/css/application/people/people-profile.css' => '2473d929',
|
||||
'rsrc/css/application/phame/phame.css' => '53fa6236',
|
||||
'rsrc/css/application/pholio/pholio-edit.css' => '07676f51',
|
||||
|
@ -97,12 +97,12 @@ return array(
|
|||
'rsrc/css/application/policy/policy.css' => '957ea14c',
|
||||
'rsrc/css/application/ponder/ponder-view.css' => 'fbd45f96',
|
||||
'rsrc/css/application/project/project-card-view.css' => 'f25746f5',
|
||||
'rsrc/css/application/project/project-view.css' => '6936dc6e',
|
||||
'rsrc/css/application/project/project-view.css' => 'ceabdbaa',
|
||||
'rsrc/css/application/releeph/releeph-core.css' => '9b3c5733',
|
||||
'rsrc/css/application/releeph/releeph-preview-branch.css' => 'b7a6f4a5',
|
||||
'rsrc/css/application/releeph/releeph-request-differential-create-dialog.css' => '8d8b92cd',
|
||||
'rsrc/css/application/releeph/releeph-request-typeahead.css' => '667a48ae',
|
||||
'rsrc/css/application/search/application-search-view.css' => '8452c849',
|
||||
'rsrc/css/application/search/application-search-view.css' => '20ae9d85',
|
||||
'rsrc/css/application/search/search-results.css' => '64ad079a',
|
||||
'rsrc/css/application/slowvote/slowvote.css' => 'a94b7230',
|
||||
'rsrc/css/application/tokens/tokens.css' => '3d0f239e',
|
||||
|
@ -113,13 +113,13 @@ return array(
|
|||
'rsrc/css/core/z-index.css' => '5e72c4e0',
|
||||
'rsrc/css/diviner/diviner-shared.css' => 'aa3656aa',
|
||||
'rsrc/css/font/font-aleo.css' => '8bdb2835',
|
||||
'rsrc/css/font/font-awesome.css' => '2b7ebbcc',
|
||||
'rsrc/css/font/font-awesome.css' => 'e838e088',
|
||||
'rsrc/css/font/font-lato.css' => 'c7ccd872',
|
||||
'rsrc/css/font/phui-font-icon-base.css' => '870a7360',
|
||||
'rsrc/css/layout/phabricator-filetree-view.css' => 'fccf9f82',
|
||||
'rsrc/css/layout/phabricator-source-code-view.css' => '4383192f',
|
||||
'rsrc/css/phui/calendar/phui-calendar-day.css' => '572b1893',
|
||||
'rsrc/css/phui/calendar/phui-calendar-list.css' => 'fcc9fb41',
|
||||
'rsrc/css/phui/calendar/phui-calendar-list.css' => 'eb5c774b',
|
||||
'rsrc/css/phui/calendar/phui-calendar-month.css' => '8e10e92c',
|
||||
'rsrc/css/phui/calendar/phui-calendar.css' => '477acfaa',
|
||||
'rsrc/css/phui/object-item/phui-oi-big-ui.css' => '19f9369b',
|
||||
|
@ -131,10 +131,10 @@ return array(
|
|||
'rsrc/css/phui/phui-action-list.css' => '5679229f',
|
||||
'rsrc/css/phui/phui-action-panel.css' => '91c7b835',
|
||||
'rsrc/css/phui/phui-badge.css' => '3baef8db',
|
||||
'rsrc/css/phui/phui-basic-nav-view.css' => '7093573b',
|
||||
'rsrc/css/phui/phui-basic-nav-view.css' => '3d4b207b',
|
||||
'rsrc/css/phui/phui-big-info-view.css' => 'bd903741',
|
||||
'rsrc/css/phui/phui-box.css' => '33b629f8',
|
||||
'rsrc/css/phui/phui-button.css' => '00ddac15',
|
||||
'rsrc/css/phui/phui-box.css' => '269cbc99',
|
||||
'rsrc/css/phui/phui-button.css' => '7eaff361',
|
||||
'rsrc/css/phui/phui-chart.css' => '6bf6f78e',
|
||||
'rsrc/css/phui/phui-cms.css' => 'be43c8a8',
|
||||
'rsrc/css/phui/phui-comment-form.css' => '48fbd65d',
|
||||
|
@ -162,17 +162,16 @@ return array(
|
|||
'rsrc/css/phui/phui-object-box.css' => '8b289e3d',
|
||||
'rsrc/css/phui/phui-pager.css' => 'bea33d23',
|
||||
'rsrc/css/phui/phui-pinboard-view.css' => '2495140e',
|
||||
'rsrc/css/phui/phui-profile-menu.css' => 'c71ecdcd',
|
||||
'rsrc/css/phui/phui-property-list-view.css' => '6d8e58ac',
|
||||
'rsrc/css/phui/phui-property-list-view.css' => '2dc7993f',
|
||||
'rsrc/css/phui/phui-remarkup-preview.css' => '1a8f2591',
|
||||
'rsrc/css/phui/phui-segment-bar-view.css' => '46342871',
|
||||
'rsrc/css/phui/phui-segment-bar-view.css' => 'b1d1b892',
|
||||
'rsrc/css/phui/phui-spacing.css' => '042804d6',
|
||||
'rsrc/css/phui/phui-status.css' => 'd5263e49',
|
||||
'rsrc/css/phui/phui-tag-view.css' => '84d65f26',
|
||||
'rsrc/css/phui/phui-timeline-view.css' => 'bc523970',
|
||||
'rsrc/css/phui/phui-two-column-view.css' => 'f63cad3c',
|
||||
'rsrc/css/phui/workboards/phui-workboard-color.css' => 'b60ef38a',
|
||||
'rsrc/css/phui/workboards/phui-workboard.css' => 'c88912ee',
|
||||
'rsrc/css/phui/phui-two-column-view.css' => '8a1074c7',
|
||||
'rsrc/css/phui/workboards/phui-workboard-color.css' => 'f0551a33',
|
||||
'rsrc/css/phui/workboards/phui-workboard.css' => '3bc85455',
|
||||
'rsrc/css/phui/workboards/phui-workcard.css' => 'cca5fa92',
|
||||
'rsrc/css/phui/workboards/phui-workpanel.css' => 'a3a63478',
|
||||
'rsrc/css/sprite-login.css' => '587d92d7',
|
||||
|
@ -189,10 +188,10 @@ return array(
|
|||
'rsrc/externals/font/aleo/aleo-regular.ttf' => '751e7479',
|
||||
'rsrc/externals/font/aleo/aleo-regular.woff' => 'c3744be9',
|
||||
'rsrc/externals/font/aleo/aleo-regular.woff2' => '851aa0ee',
|
||||
'rsrc/externals/font/fontawesome/fontawesome-webfont.eot' => '59b3076c',
|
||||
'rsrc/externals/font/fontawesome/fontawesome-webfont.ttf' => '45ad7e57',
|
||||
'rsrc/externals/font/fontawesome/fontawesome-webfont.woff' => 'f861e2a8',
|
||||
'rsrc/externals/font/fontawesome/fontawesome-webfont.woff2' => '0ee0f078',
|
||||
'rsrc/externals/font/fontawesome/fontawesome-webfont.eot' => '24a7064f',
|
||||
'rsrc/externals/font/fontawesome/fontawesome-webfont.ttf' => '0039fe26',
|
||||
'rsrc/externals/font/fontawesome/fontawesome-webfont.woff' => 'de978a43',
|
||||
'rsrc/externals/font/fontawesome/fontawesome-webfont.woff2' => '2a832057',
|
||||
'rsrc/externals/font/lato/lato-bold.eot' => '99fbcf8c',
|
||||
'rsrc/externals/font/lato/lato-bold.svg' => '2aa83045',
|
||||
'rsrc/externals/font/lato/lato-bold.ttf' => '0a7141f7',
|
||||
|
@ -488,7 +487,7 @@ return array(
|
|||
'rsrc/js/core/ShapedRequest.js' => '7cbe244b',
|
||||
'rsrc/js/core/TextAreaUtils.js' => '320810c8',
|
||||
'rsrc/js/core/Title.js' => '485aaa6c',
|
||||
'rsrc/js/core/ToolTip.js' => 'b5c62c3b',
|
||||
'rsrc/js/core/ToolTip.js' => '8fadb715',
|
||||
'rsrc/js/core/behavior-active-nav.js' => 'e379b58e',
|
||||
'rsrc/js/core/behavior-audio-source.js' => '59b251eb',
|
||||
'rsrc/js/core/behavior-autofocus.js' => '7319e029',
|
||||
|
@ -529,7 +528,7 @@ return array(
|
|||
'rsrc/js/core/behavior-time-typeahead.js' => '522431f7',
|
||||
'rsrc/js/core/behavior-toggle-class.js' => '92b9ec77',
|
||||
'rsrc/js/core/behavior-tokenizer.js' => 'b3a4b884',
|
||||
'rsrc/js/core/behavior-tooltip.js' => '42fcb747',
|
||||
'rsrc/js/core/behavior-tooltip.js' => 'c420b0b9',
|
||||
'rsrc/js/core/behavior-user-menu.js' => '31420f77',
|
||||
'rsrc/js/core/behavior-watch-anchor.js' => '9f36c42d',
|
||||
'rsrc/js/core/behavior-workflow.js' => '0a3f3021',
|
||||
|
@ -553,11 +552,11 @@ return array(
|
|||
'aphront-list-filter-view-css' => '5d6f0526',
|
||||
'aphront-multi-column-view-css' => '84cc6640',
|
||||
'aphront-panel-view-css' => '8427b78d',
|
||||
'aphront-table-view-css' => '3225137a',
|
||||
'aphront-table-view-css' => '213a5981',
|
||||
'aphront-tokenizer-control-css' => '9a8cb501',
|
||||
'aphront-tooltip-css' => '1a07aea8',
|
||||
'aphront-tooltip-css' => '173b9431',
|
||||
'aphront-typeahead-control-css' => 'd4f16145',
|
||||
'application-search-view-css' => '8452c849',
|
||||
'application-search-view-css' => '20ae9d85',
|
||||
'auth-css' => '0877ed6e',
|
||||
'bulk-job-css' => 'df9c1d4a',
|
||||
'changeset-view-manager' => 'a2828756',
|
||||
|
@ -583,10 +582,10 @@ return array(
|
|||
'differential-table-of-contents-css' => 'ae4b7a55',
|
||||
'diffusion-icons-css' => 'd678600a',
|
||||
'diffusion-readme-css' => '297373eb',
|
||||
'diffusion-source-css' => '68b30fd3',
|
||||
'diffusion-source-css' => '750add59',
|
||||
'diviner-shared-css' => 'aa3656aa',
|
||||
'font-aleo' => '8bdb2835',
|
||||
'font-fontawesome' => '2b7ebbcc',
|
||||
'font-fontawesome' => 'e838e088',
|
||||
'font-lato' => 'c7ccd872',
|
||||
'global-drag-and-drop-css' => '5c1b47c2',
|
||||
'harbormaster-css' => 'f491c9f4',
|
||||
|
@ -681,7 +680,7 @@ return array(
|
|||
'javelin-behavior-phabricator-reveal-content' => '60821bc7',
|
||||
'javelin-behavior-phabricator-search-typeahead' => '06c32383',
|
||||
'javelin-behavior-phabricator-show-older-transactions' => '94c65b72',
|
||||
'javelin-behavior-phabricator-tooltips' => '42fcb747',
|
||||
'javelin-behavior-phabricator-tooltips' => 'c420b0b9',
|
||||
'javelin-behavior-phabricator-transaction-comment-form' => 'b23b49e6',
|
||||
'javelin-behavior-phabricator-transaction-list' => '13c739ea',
|
||||
'javelin-behavior-phabricator-watch-anchor' => '9f36c42d',
|
||||
|
@ -779,9 +778,9 @@ return array(
|
|||
'owners-path-editor-css' => '2f00933b',
|
||||
'paste-css' => '1898e534',
|
||||
'path-typeahead' => 'f7fc67ec',
|
||||
'people-picture-menu-item-css' => '1ac65ef7',
|
||||
'people-profile-css' => '2473d929',
|
||||
'phabricator-action-list-view-css' => '5679229f',
|
||||
'phabricator-application-launch-view-css' => '95351601',
|
||||
'phabricator-busy' => '59a7976a',
|
||||
'phabricator-chatlog-css' => 'd295b020',
|
||||
'phabricator-content-source-view-css' => '4b8b05d4',
|
||||
|
@ -798,7 +797,7 @@ return array(
|
|||
'phabricator-flag-css' => 'bba8f811',
|
||||
'phabricator-keyboard-shortcut' => '1ae869f2',
|
||||
'phabricator-keyboard-shortcut-manager' => '4a021c10',
|
||||
'phabricator-main-menu-view' => '8eac4166',
|
||||
'phabricator-main-menu-view' => '62c04564',
|
||||
'phabricator-nav-view-css' => 'b29426e9',
|
||||
'phabricator-notification' => 'ccf1cbf8',
|
||||
'phabricator-notification-css' => '3f6c89c9',
|
||||
|
@ -814,7 +813,7 @@ return array(
|
|||
'phabricator-standard-page-view' => '894d8a25',
|
||||
'phabricator-textareautils' => '320810c8',
|
||||
'phabricator-title' => '485aaa6c',
|
||||
'phabricator-tooltip' => 'b5c62c3b',
|
||||
'phabricator-tooltip' => '8fadb715',
|
||||
'phabricator-ui-example-css' => '528b19de',
|
||||
'phabricator-uiexample-javelin-view' => 'd4a14807',
|
||||
'phabricator-uiexample-reactor-button' => 'd19198c8',
|
||||
|
@ -839,13 +838,13 @@ return array(
|
|||
'phriction-document-css' => '4282e4ad',
|
||||
'phui-action-panel-css' => '91c7b835',
|
||||
'phui-badge-view-css' => '3baef8db',
|
||||
'phui-basic-nav-view-css' => '7093573b',
|
||||
'phui-basic-nav-view-css' => '3d4b207b',
|
||||
'phui-big-info-view-css' => 'bd903741',
|
||||
'phui-box-css' => '33b629f8',
|
||||
'phui-button-css' => '00ddac15',
|
||||
'phui-box-css' => '269cbc99',
|
||||
'phui-button-css' => '7eaff361',
|
||||
'phui-calendar-css' => '477acfaa',
|
||||
'phui-calendar-day-css' => '572b1893',
|
||||
'phui-calendar-list-css' => 'fcc9fb41',
|
||||
'phui-calendar-list-css' => 'eb5c774b',
|
||||
'phui-calendar-month-css' => '8e10e92c',
|
||||
'phui-chart-css' => '6bf6f78e',
|
||||
'phui-cms-css' => 'be43c8a8',
|
||||
|
@ -883,18 +882,17 @@ return array(
|
|||
'phui-oi-simple-ui-css' => 'a8beebea',
|
||||
'phui-pager-css' => 'bea33d23',
|
||||
'phui-pinboard-view-css' => '2495140e',
|
||||
'phui-profile-menu-css' => 'c71ecdcd',
|
||||
'phui-property-list-view-css' => '6d8e58ac',
|
||||
'phui-property-list-view-css' => '2dc7993f',
|
||||
'phui-remarkup-preview-css' => '1a8f2591',
|
||||
'phui-segment-bar-view-css' => '46342871',
|
||||
'phui-segment-bar-view-css' => 'b1d1b892',
|
||||
'phui-spacing-css' => '042804d6',
|
||||
'phui-status-list-view-css' => 'd5263e49',
|
||||
'phui-tag-view-css' => '84d65f26',
|
||||
'phui-theme-css' => '798c69b8',
|
||||
'phui-theme-css' => '9f261c6b',
|
||||
'phui-timeline-view-css' => 'bc523970',
|
||||
'phui-two-column-view-css' => 'f63cad3c',
|
||||
'phui-workboard-color-css' => 'b60ef38a',
|
||||
'phui-workboard-view-css' => 'c88912ee',
|
||||
'phui-two-column-view-css' => '8a1074c7',
|
||||
'phui-workboard-color-css' => 'f0551a33',
|
||||
'phui-workboard-view-css' => '3bc85455',
|
||||
'phui-workcard-view-css' => 'cca5fa92',
|
||||
'phui-workpanel-view-css' => 'a3a63478',
|
||||
'phuix-action-list-view' => 'b5c256b8',
|
||||
|
@ -908,7 +906,7 @@ return array(
|
|||
'policy-transaction-detail-css' => '82100a43',
|
||||
'ponder-view-css' => 'fbd45f96',
|
||||
'project-card-view-css' => 'f25746f5',
|
||||
'project-view-css' => '6936dc6e',
|
||||
'project-view-css' => 'ceabdbaa',
|
||||
'releeph-core' => '9b3c5733',
|
||||
'releeph-preview-branch' => 'b7a6f4a5',
|
||||
'releeph-request-differential-create-dialog' => '8d8b92cd',
|
||||
|
@ -1178,12 +1176,6 @@ return array(
|
|||
'javelin-dom',
|
||||
'javelin-request',
|
||||
),
|
||||
'42fcb747' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-behavior-device',
|
||||
'javelin-stratcom',
|
||||
'phabricator-tooltip',
|
||||
),
|
||||
'44959b73' => array(
|
||||
'javelin-util',
|
||||
'javelin-uri',
|
||||
|
@ -1375,6 +1367,9 @@ return array(
|
|||
'javelin-magical-init',
|
||||
'javelin-util',
|
||||
),
|
||||
'62c04564' => array(
|
||||
'phui-theme-css',
|
||||
),
|
||||
'62dfea03' => array(
|
||||
'javelin-install',
|
||||
'javelin-util',
|
||||
|
@ -1612,8 +1607,11 @@ return array(
|
|||
'javelin-stratcom',
|
||||
'javelin-util',
|
||||
),
|
||||
'8eac4166' => array(
|
||||
'phui-theme-css',
|
||||
'8fadb715' => array(
|
||||
'javelin-install',
|
||||
'javelin-util',
|
||||
'javelin-dom',
|
||||
'javelin-vector',
|
||||
),
|
||||
'8ff5e24c' => array(
|
||||
'javelin-behavior',
|
||||
|
@ -1888,12 +1886,6 @@ return array(
|
|||
'javelin-install',
|
||||
'javelin-dom',
|
||||
),
|
||||
'b5c62c3b' => array(
|
||||
'javelin-install',
|
||||
'javelin-util',
|
||||
'javelin-dom',
|
||||
'javelin-vector',
|
||||
),
|
||||
'b5d57730' => array(
|
||||
'javelin-install',
|
||||
'javelin-stratcom',
|
||||
|
@ -1969,6 +1961,12 @@ return array(
|
|||
'javelin-install',
|
||||
'javelin-dom',
|
||||
),
|
||||
'c420b0b9' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-behavior-device',
|
||||
'javelin-stratcom',
|
||||
'phabricator-tooltip',
|
||||
),
|
||||
'c587b80f' => array(
|
||||
'javelin-install',
|
||||
),
|
||||
|
@ -2318,8 +2316,6 @@ return array(
|
|||
'phui-spacing-css',
|
||||
'phui-form-css',
|
||||
'phui-icon-view-css',
|
||||
'phui-profile-menu-css',
|
||||
'phabricator-application-launch-view-css',
|
||||
'phabricator-action-list-view-css',
|
||||
'phui-property-list-view-css',
|
||||
'phui-tag-view-css',
|
||||
|
|
|
@ -130,9 +130,7 @@ return array(
|
|||
'phui-spacing-css',
|
||||
'phui-form-css',
|
||||
'phui-icon-view-css',
|
||||
'phui-profile-menu-css',
|
||||
|
||||
'phabricator-application-launch-view-css',
|
||||
'phabricator-action-list-view-css',
|
||||
'phui-property-list-view-css',
|
||||
'phui-tag-view-css',
|
||||
|
|
45
resources/sql/autopatches/20170131.dashboard.personal.01.php
Normal file
45
resources/sql/autopatches/20170131.dashboard.personal.01.php
Normal file
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
|
||||
$table = new PhabricatorDashboard();
|
||||
$conn = $table->establishConnection('r');
|
||||
$table_name = 'dashboard_install';
|
||||
|
||||
$search_table = new PhabricatorProfileMenuItemConfiguration();
|
||||
$search_conn = $search_table->establishConnection('w');
|
||||
$search_table_name = 'search_profilepanelconfiguration';
|
||||
|
||||
$viewer = PhabricatorUser::getOmnipotentUser();
|
||||
$profile_phid = id(new PhabricatorHomeApplication())->getPHID();
|
||||
$menu_item_key = PhabricatorDashboardProfileMenuItem::MENUITEMKEY;
|
||||
|
||||
foreach (new LiskRawMigrationIterator($conn, $table_name) as $install) {
|
||||
|
||||
$dashboard_phid = $install['dashboardPHID'];
|
||||
$new_phid = id(new PhabricatorProfileMenuItemConfiguration())->generatePHID();
|
||||
$menu_item_properties = json_encode(
|
||||
array('dashboardPHID' => $dashboard_phid, 'name' => ''));
|
||||
|
||||
$custom_phid = $install['objectPHID'];
|
||||
if ($custom_phid == 'dashboard:default') {
|
||||
$custom_phid = null;
|
||||
}
|
||||
|
||||
$menu_item_order = 0;
|
||||
|
||||
queryfx(
|
||||
$search_conn,
|
||||
'INSERT INTO %T (phid, profilePHID, menuItemKey, menuItemProperties, '.
|
||||
'visibility, dateCreated, dateModified, menuItemOrder, customPHID) VALUES '.
|
||||
'(%s, %s, %s, %s, %s, %d, %d, %d, %ns)',
|
||||
$search_table_name,
|
||||
$new_phid,
|
||||
$profile_phid,
|
||||
$menu_item_key,
|
||||
$menu_item_properties,
|
||||
'visible',
|
||||
PhabricatorTime::getNow(),
|
||||
PhabricatorTime::getNow(),
|
||||
$menu_item_order,
|
||||
$custom_phid);
|
||||
|
||||
}
|
|
@ -635,6 +635,7 @@ phutil_register_library_map(array(
|
|||
'DiffusionCommitEditController' => 'applications/diffusion/controller/DiffusionCommitEditController.php',
|
||||
'DiffusionCommitEditEngine' => 'applications/diffusion/editor/DiffusionCommitEditEngine.php',
|
||||
'DiffusionCommitFulltextEngine' => 'applications/repository/search/DiffusionCommitFulltextEngine.php',
|
||||
'DiffusionCommitHasPackageEdgeType' => 'applications/diffusion/edge/DiffusionCommitHasPackageEdgeType.php',
|
||||
'DiffusionCommitHasRevisionEdgeType' => 'applications/diffusion/edge/DiffusionCommitHasRevisionEdgeType.php',
|
||||
'DiffusionCommitHasRevisionRelationship' => 'applications/diffusion/relationships/DiffusionCommitHasRevisionRelationship.php',
|
||||
'DiffusionCommitHasTaskEdgeType' => 'applications/diffusion/edge/DiffusionCommitHasTaskEdgeType.php',
|
||||
|
@ -1209,6 +1210,9 @@ phutil_register_library_map(array(
|
|||
'HarbormasterBuildableTransactionEditor' => 'applications/harbormaster/editor/HarbormasterBuildableTransactionEditor.php',
|
||||
'HarbormasterBuildableTransactionQuery' => 'applications/harbormaster/query/HarbormasterBuildableTransactionQuery.php',
|
||||
'HarbormasterBuildableViewController' => 'applications/harbormaster/controller/HarbormasterBuildableViewController.php',
|
||||
'HarbormasterBuildkiteBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterBuildkiteBuildStepImplementation.php',
|
||||
'HarbormasterBuildkiteBuildableInterface' => 'applications/harbormaster/interface/HarbormasterBuildkiteBuildableInterface.php',
|
||||
'HarbormasterBuildkiteHookController' => 'applications/harbormaster/controller/HarbormasterBuildkiteHookController.php',
|
||||
'HarbormasterBuiltinBuildStepGroup' => 'applications/harbormaster/stepgroup/HarbormasterBuiltinBuildStepGroup.php',
|
||||
'HarbormasterCircleCIBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterCircleCIBuildStepImplementation.php',
|
||||
'HarbormasterCircleCIBuildableInterface' => 'applications/harbormaster/interface/HarbormasterCircleCIBuildableInterface.php',
|
||||
|
@ -1684,6 +1688,7 @@ phutil_register_library_map(array(
|
|||
'PHUIHandleView' => 'applications/phid/view/PHUIHandleView.php',
|
||||
'PHUIHeadThingView' => 'view/phui/PHUIHeadThingView.php',
|
||||
'PHUIHeaderView' => 'view/phui/PHUIHeaderView.php',
|
||||
'PHUIHomeView' => 'applications/home/view/PHUIHomeView.php',
|
||||
'PHUIHovercardUIExample' => 'applications/uiexample/examples/PHUIHovercardUIExample.php',
|
||||
'PHUIHovercardView' => 'view/phui/PHUIHovercardView.php',
|
||||
'PHUIIconCircleView' => 'view/phui/PHUIIconCircleView.php',
|
||||
|
@ -1824,7 +1829,6 @@ phutil_register_library_map(array(
|
|||
'PhabricatorApplicationEditController' => 'applications/meta/controller/PhabricatorApplicationEditController.php',
|
||||
'PhabricatorApplicationEditHTTPParameterHelpView' => 'applications/transactions/view/PhabricatorApplicationEditHTTPParameterHelpView.php',
|
||||
'PhabricatorApplicationEmailCommandsController' => 'applications/meta/controller/PhabricatorApplicationEmailCommandsController.php',
|
||||
'PhabricatorApplicationLaunchView' => 'applications/meta/view/PhabricatorApplicationLaunchView.php',
|
||||
'PhabricatorApplicationPanelController' => 'applications/meta/controller/PhabricatorApplicationPanelController.php',
|
||||
'PhabricatorApplicationProfileMenuItem' => 'applications/search/menuitem/PhabricatorApplicationProfileMenuItem.php',
|
||||
'PhabricatorApplicationQuery' => 'applications/meta/query/PhabricatorApplicationQuery.php',
|
||||
|
@ -1887,10 +1891,12 @@ phutil_register_library_map(array(
|
|||
'PhabricatorAuditManagementWorkflow' => 'applications/audit/management/PhabricatorAuditManagementWorkflow.php',
|
||||
'PhabricatorAuditReplyHandler' => 'applications/audit/mail/PhabricatorAuditReplyHandler.php',
|
||||
'PhabricatorAuditStatusConstants' => 'applications/audit/constants/PhabricatorAuditStatusConstants.php',
|
||||
'PhabricatorAuditSynchronizeManagementWorkflow' => 'applications/audit/management/PhabricatorAuditSynchronizeManagementWorkflow.php',
|
||||
'PhabricatorAuditTransaction' => 'applications/audit/storage/PhabricatorAuditTransaction.php',
|
||||
'PhabricatorAuditTransactionComment' => 'applications/audit/storage/PhabricatorAuditTransactionComment.php',
|
||||
'PhabricatorAuditTransactionQuery' => 'applications/audit/query/PhabricatorAuditTransactionQuery.php',
|
||||
'PhabricatorAuditTransactionView' => 'applications/audit/view/PhabricatorAuditTransactionView.php',
|
||||
'PhabricatorAuditUpdateOwnersManagementWorkflow' => 'applications/audit/management/PhabricatorAuditUpdateOwnersManagementWorkflow.php',
|
||||
'PhabricatorAuthAccountView' => 'applications/auth/view/PhabricatorAuthAccountView.php',
|
||||
'PhabricatorAuthApplication' => 'applications/auth/application/PhabricatorAuthApplication.php',
|
||||
'PhabricatorAuthAuthFactorPHIDType' => 'applications/auth/phid/PhabricatorAuthAuthFactorPHIDType.php',
|
||||
|
@ -2467,7 +2473,6 @@ phutil_register_library_map(array(
|
|||
'PhabricatorDashboardEditController' => 'applications/dashboard/controller/PhabricatorDashboardEditController.php',
|
||||
'PhabricatorDashboardIconSet' => 'applications/dashboard/icon/PhabricatorDashboardIconSet.php',
|
||||
'PhabricatorDashboardInstall' => 'applications/dashboard/storage/PhabricatorDashboardInstall.php',
|
||||
'PhabricatorDashboardInstallController' => 'applications/dashboard/controller/PhabricatorDashboardInstallController.php',
|
||||
'PhabricatorDashboardLayoutConfig' => 'applications/dashboard/layoutconfig/PhabricatorDashboardLayoutConfig.php',
|
||||
'PhabricatorDashboardListController' => 'applications/dashboard/controller/PhabricatorDashboardListController.php',
|
||||
'PhabricatorDashboardManageController' => 'applications/dashboard/controller/PhabricatorDashboardManageController.php',
|
||||
|
@ -2673,7 +2678,6 @@ phutil_register_library_map(array(
|
|||
'PhabricatorFactUpdateIterator' => 'applications/fact/extract/PhabricatorFactUpdateIterator.php',
|
||||
'PhabricatorFavoritesApplication' => 'applications/favorites/application/PhabricatorFavoritesApplication.php',
|
||||
'PhabricatorFavoritesController' => 'applications/favorites/controller/PhabricatorFavoritesController.php',
|
||||
'PhabricatorFavoritesMainController' => 'applications/favorites/controller/PhabricatorFavoritesMainController.php',
|
||||
'PhabricatorFavoritesMainMenuBarExtension' => 'applications/favorites/engineextension/PhabricatorFavoritesMainMenuBarExtension.php',
|
||||
'PhabricatorFavoritesMenuItemController' => 'applications/favorites/controller/PhabricatorFavoritesMenuItemController.php',
|
||||
'PhabricatorFavoritesProfileMenuEngine' => 'applications/favorites/engine/PhabricatorFavoritesProfileMenuEngine.php',
|
||||
|
@ -2835,17 +2839,16 @@ phutil_register_library_map(array(
|
|||
'PhabricatorHomeApplication' => 'applications/home/application/PhabricatorHomeApplication.php',
|
||||
'PhabricatorHomeConstants' => 'applications/home/constants/PhabricatorHomeConstants.php',
|
||||
'PhabricatorHomeController' => 'applications/home/controller/PhabricatorHomeController.php',
|
||||
'PhabricatorHomeMainController' => 'applications/home/controller/PhabricatorHomeMainController.php',
|
||||
'PhabricatorHomeManageProfileMenuItem' => 'applications/home/menuitem/PhabricatorHomeManageProfileMenuItem.php',
|
||||
'PhabricatorHomeMenuController' => 'applications/home/controller/PhabricatorHomeMenuController.php',
|
||||
'PhabricatorHomeLauncherProfileMenuItem' => 'applications/home/menuitem/PhabricatorHomeLauncherProfileMenuItem.php',
|
||||
'PhabricatorHomeMenuItemController' => 'applications/home/controller/PhabricatorHomeMenuItemController.php',
|
||||
'PhabricatorHomePreferencesSettingsPanel' => 'applications/settings/panel/PhabricatorHomePreferencesSettingsPanel.php',
|
||||
'PhabricatorHomeProfileMenuEngine' => 'applications/home/engine/PhabricatorHomeProfileMenuEngine.php',
|
||||
'PhabricatorHomeProfileMenuItem' => 'applications/home/menuitem/PhabricatorHomeProfileMenuItem.php',
|
||||
'PhabricatorHovercardEngineExtension' => 'applications/search/engineextension/PhabricatorHovercardEngineExtension.php',
|
||||
'PhabricatorHovercardEngineExtensionModule' => 'applications/search/engineextension/PhabricatorHovercardEngineExtensionModule.php',
|
||||
'PhabricatorIDsSearchEngineExtension' => 'applications/search/engineextension/PhabricatorIDsSearchEngineExtension.php',
|
||||
'PhabricatorIDsSearchField' => 'applications/search/field/PhabricatorIDsSearchField.php',
|
||||
'PhabricatorIRCProtocolAdapter' => 'infrastructure/daemon/bot/adapter/PhabricatorIRCProtocolAdapter.php',
|
||||
'PhabricatorIconDatasource' => 'applications/files/typeahead/PhabricatorIconDatasource.php',
|
||||
'PhabricatorIconRemarkupRule' => 'applications/macro/markup/PhabricatorIconRemarkupRule.php',
|
||||
'PhabricatorIconSet' => 'applications/files/iconset/PhabricatorIconSet.php',
|
||||
'PhabricatorIconSetEditField' => 'applications/transactions/editfield/PhabricatorIconSetEditField.php',
|
||||
|
@ -2881,6 +2884,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorKeyring' => 'applications/files/keyring/PhabricatorKeyring.php',
|
||||
'PhabricatorKeyringConfigOptionType' => 'applications/files/keyring/PhabricatorKeyringConfigOptionType.php',
|
||||
'PhabricatorLDAPAuthProvider' => 'applications/auth/provider/PhabricatorLDAPAuthProvider.php',
|
||||
'PhabricatorLabelProfileMenuItem' => 'applications/search/menuitem/PhabricatorLabelProfileMenuItem.php',
|
||||
'PhabricatorLegalpadApplication' => 'applications/legalpad/application/PhabricatorLegalpadApplication.php',
|
||||
'PhabricatorLegalpadConfigOptions' => 'applications/legalpad/config/PhabricatorLegalpadConfigOptions.php',
|
||||
'PhabricatorLegalpadDocumentPHIDType' => 'applications/legalpad/phid/PhabricatorLegalpadDocumentPHIDType.php',
|
||||
|
@ -2960,6 +2964,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorMainMenuBarExtension' => 'view/page/menu/PhabricatorMainMenuBarExtension.php',
|
||||
'PhabricatorMainMenuSearchView' => 'view/page/menu/PhabricatorMainMenuSearchView.php',
|
||||
'PhabricatorMainMenuView' => 'view/page/menu/PhabricatorMainMenuView.php',
|
||||
'PhabricatorManageProfileMenuItem' => 'applications/search/menuitem/PhabricatorManageProfileMenuItem.php',
|
||||
'PhabricatorManagementWorkflow' => 'infrastructure/management/PhabricatorManagementWorkflow.php',
|
||||
'PhabricatorManiphestApplication' => 'applications/maniphest/application/PhabricatorManiphestApplication.php',
|
||||
'PhabricatorManiphestConfigOptions' => 'applications/maniphest/config/PhabricatorManiphestConfigOptions.php',
|
||||
|
@ -3319,6 +3324,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorPeopleNewController' => 'applications/people/controller/PhabricatorPeopleNewController.php',
|
||||
'PhabricatorPeopleNoOwnerDatasource' => 'applications/people/typeahead/PhabricatorPeopleNoOwnerDatasource.php',
|
||||
'PhabricatorPeopleOwnerDatasource' => 'applications/people/typeahead/PhabricatorPeopleOwnerDatasource.php',
|
||||
'PhabricatorPeoplePictureProfileMenuItem' => 'applications/people/menuitem/PhabricatorPeoplePictureProfileMenuItem.php',
|
||||
'PhabricatorPeopleProfileController' => 'applications/people/controller/PhabricatorPeopleProfileController.php',
|
||||
'PhabricatorPeopleProfileEditController' => 'applications/people/controller/PhabricatorPeopleProfileEditController.php',
|
||||
'PhabricatorPeopleProfileManageController' => 'applications/people/controller/PhabricatorPeopleProfileManageController.php',
|
||||
|
@ -5088,6 +5094,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorExtendedPolicyInterface',
|
||||
'HarbormasterBuildableInterface',
|
||||
'HarbormasterCircleCIBuildableInterface',
|
||||
'HarbormasterBuildkiteBuildableInterface',
|
||||
'PhabricatorApplicationTransactionInterface',
|
||||
'PhabricatorDestructibleInterface',
|
||||
),
|
||||
|
@ -5343,6 +5350,7 @@ phutil_register_library_map(array(
|
|||
'DiffusionCommitEditController' => 'DiffusionController',
|
||||
'DiffusionCommitEditEngine' => 'PhabricatorEditEngine',
|
||||
'DiffusionCommitFulltextEngine' => 'PhabricatorFulltextEngine',
|
||||
'DiffusionCommitHasPackageEdgeType' => 'PhabricatorEdgeType',
|
||||
'DiffusionCommitHasRevisionEdgeType' => 'PhabricatorEdgeType',
|
||||
'DiffusionCommitHasRevisionRelationship' => 'DiffusionCommitRelationship',
|
||||
'DiffusionCommitHasTaskEdgeType' => 'PhabricatorEdgeType',
|
||||
|
@ -6014,6 +6022,8 @@ phutil_register_library_map(array(
|
|||
'HarbormasterBuildableTransactionEditor' => 'PhabricatorApplicationTransactionEditor',
|
||||
'HarbormasterBuildableTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
||||
'HarbormasterBuildableViewController' => 'HarbormasterController',
|
||||
'HarbormasterBuildkiteBuildStepImplementation' => 'HarbormasterBuildStepImplementation',
|
||||
'HarbormasterBuildkiteHookController' => 'HarbormasterController',
|
||||
'HarbormasterBuiltinBuildStepGroup' => 'HarbormasterBuildStepGroup',
|
||||
'HarbormasterCircleCIBuildStepImplementation' => 'HarbormasterBuildStepImplementation',
|
||||
'HarbormasterCircleCIHookController' => 'HarbormasterController',
|
||||
|
@ -6556,6 +6566,7 @@ phutil_register_library_map(array(
|
|||
'PHUIHandleView' => 'AphrontView',
|
||||
'PHUIHeadThingView' => 'AphrontTagView',
|
||||
'PHUIHeaderView' => 'AphrontTagView',
|
||||
'PHUIHomeView' => 'AphrontTagView',
|
||||
'PHUIHovercardUIExample' => 'PhabricatorUIExample',
|
||||
'PHUIHovercardView' => 'AphrontTagView',
|
||||
'PHUIIconCircleView' => 'AphrontTagView',
|
||||
|
@ -6708,7 +6719,6 @@ phutil_register_library_map(array(
|
|||
'PhabricatorApplicationEditController' => 'PhabricatorApplicationsController',
|
||||
'PhabricatorApplicationEditHTTPParameterHelpView' => 'AphrontView',
|
||||
'PhabricatorApplicationEmailCommandsController' => 'PhabricatorApplicationsController',
|
||||
'PhabricatorApplicationLaunchView' => 'AphrontTagView',
|
||||
'PhabricatorApplicationPanelController' => 'PhabricatorApplicationsController',
|
||||
'PhabricatorApplicationProfileMenuItem' => 'PhabricatorProfileMenuItem',
|
||||
'PhabricatorApplicationQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||
|
@ -6782,10 +6792,12 @@ phutil_register_library_map(array(
|
|||
'PhabricatorAuditManagementWorkflow' => 'PhabricatorManagementWorkflow',
|
||||
'PhabricatorAuditReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler',
|
||||
'PhabricatorAuditStatusConstants' => 'Phobject',
|
||||
'PhabricatorAuditSynchronizeManagementWorkflow' => 'PhabricatorAuditManagementWorkflow',
|
||||
'PhabricatorAuditTransaction' => 'PhabricatorModularTransaction',
|
||||
'PhabricatorAuditTransactionComment' => 'PhabricatorApplicationTransactionComment',
|
||||
'PhabricatorAuditTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
||||
'PhabricatorAuditTransactionView' => 'PhabricatorApplicationTransactionView',
|
||||
'PhabricatorAuditUpdateOwnersManagementWorkflow' => 'PhabricatorAuditManagementWorkflow',
|
||||
'PhabricatorAuthAccountView' => 'AphrontView',
|
||||
'PhabricatorAuthApplication' => 'PhabricatorApplication',
|
||||
'PhabricatorAuthAuthFactorPHIDType' => 'PhabricatorPHIDType',
|
||||
|
@ -7467,7 +7479,6 @@ phutil_register_library_map(array(
|
|||
'PhabricatorDashboardEditController' => 'PhabricatorDashboardController',
|
||||
'PhabricatorDashboardIconSet' => 'PhabricatorIconSet',
|
||||
'PhabricatorDashboardInstall' => 'PhabricatorDashboardDAO',
|
||||
'PhabricatorDashboardInstallController' => 'PhabricatorDashboardController',
|
||||
'PhabricatorDashboardLayoutConfig' => 'Phobject',
|
||||
'PhabricatorDashboardListController' => 'PhabricatorDashboardController',
|
||||
'PhabricatorDashboardManageController' => 'PhabricatorDashboardController',
|
||||
|
@ -7691,7 +7702,6 @@ phutil_register_library_map(array(
|
|||
'PhabricatorFactUpdateIterator' => 'PhutilBufferedIterator',
|
||||
'PhabricatorFavoritesApplication' => 'PhabricatorApplication',
|
||||
'PhabricatorFavoritesController' => 'PhabricatorController',
|
||||
'PhabricatorFavoritesMainController' => 'PhabricatorFavoritesController',
|
||||
'PhabricatorFavoritesMainMenuBarExtension' => 'PhabricatorMainMenuBarExtension',
|
||||
'PhabricatorFavoritesMenuItemController' => 'PhabricatorFavoritesController',
|
||||
'PhabricatorFavoritesProfileMenuEngine' => 'PhabricatorProfileMenuEngine',
|
||||
|
@ -7889,17 +7899,16 @@ phutil_register_library_map(array(
|
|||
'PhabricatorHomeApplication' => 'PhabricatorApplication',
|
||||
'PhabricatorHomeConstants' => 'PhabricatorHomeController',
|
||||
'PhabricatorHomeController' => 'PhabricatorController',
|
||||
'PhabricatorHomeMainController' => 'PhabricatorHomeController',
|
||||
'PhabricatorHomeManageProfileMenuItem' => 'PhabricatorProfileMenuItem',
|
||||
'PhabricatorHomeMenuController' => 'PhabricatorHomeController',
|
||||
'PhabricatorHomeLauncherProfileMenuItem' => 'PhabricatorProfileMenuItem',
|
||||
'PhabricatorHomeMenuItemController' => 'PhabricatorHomeController',
|
||||
'PhabricatorHomePreferencesSettingsPanel' => 'PhabricatorSettingsPanel',
|
||||
'PhabricatorHomeProfileMenuEngine' => 'PhabricatorProfileMenuEngine',
|
||||
'PhabricatorHomeProfileMenuItem' => 'PhabricatorProfileMenuItem',
|
||||
'PhabricatorHovercardEngineExtension' => 'Phobject',
|
||||
'PhabricatorHovercardEngineExtensionModule' => 'PhabricatorConfigModule',
|
||||
'PhabricatorIDsSearchEngineExtension' => 'PhabricatorSearchEngineExtension',
|
||||
'PhabricatorIDsSearchField' => 'PhabricatorSearchField',
|
||||
'PhabricatorIRCProtocolAdapter' => 'PhabricatorProtocolAdapter',
|
||||
'PhabricatorIconDatasource' => 'PhabricatorTypeaheadDatasource',
|
||||
'PhabricatorIconRemarkupRule' => 'PhutilRemarkupRule',
|
||||
'PhabricatorIconSet' => 'Phobject',
|
||||
'PhabricatorIconSetEditField' => 'PhabricatorEditField',
|
||||
|
@ -7935,6 +7944,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorKeyring' => 'Phobject',
|
||||
'PhabricatorKeyringConfigOptionType' => 'PhabricatorConfigJSONOptionType',
|
||||
'PhabricatorLDAPAuthProvider' => 'PhabricatorAuthProvider',
|
||||
'PhabricatorLabelProfileMenuItem' => 'PhabricatorProfileMenuItem',
|
||||
'PhabricatorLegalpadApplication' => 'PhabricatorApplication',
|
||||
'PhabricatorLegalpadConfigOptions' => 'PhabricatorApplicationConfigOptions',
|
||||
'PhabricatorLegalpadDocumentPHIDType' => 'PhabricatorPHIDType',
|
||||
|
@ -8014,6 +8024,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorMainMenuBarExtension' => 'Phobject',
|
||||
'PhabricatorMainMenuSearchView' => 'AphrontView',
|
||||
'PhabricatorMainMenuView' => 'AphrontView',
|
||||
'PhabricatorManageProfileMenuItem' => 'PhabricatorProfileMenuItem',
|
||||
'PhabricatorManagementWorkflow' => 'PhutilArgumentWorkflow',
|
||||
'PhabricatorManiphestApplication' => 'PhabricatorApplication',
|
||||
'PhabricatorManiphestConfigOptions' => 'PhabricatorApplicationConfigOptions',
|
||||
|
@ -8447,6 +8458,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorPeopleNewController' => 'PhabricatorPeopleController',
|
||||
'PhabricatorPeopleNoOwnerDatasource' => 'PhabricatorTypeaheadDatasource',
|
||||
'PhabricatorPeopleOwnerDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
|
||||
'PhabricatorPeoplePictureProfileMenuItem' => 'PhabricatorProfileMenuItem',
|
||||
'PhabricatorPeopleProfileController' => 'PhabricatorPeopleController',
|
||||
'PhabricatorPeopleProfileEditController' => 'PhabricatorPeopleProfileController',
|
||||
'PhabricatorPeopleProfileManageController' => 'PhabricatorPeopleProfileController',
|
||||
|
@ -8783,6 +8795,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorMentionableInterface',
|
||||
'HarbormasterBuildableInterface',
|
||||
'HarbormasterCircleCIBuildableInterface',
|
||||
'HarbormasterBuildkiteBuildableInterface',
|
||||
'PhabricatorCustomFieldInterface',
|
||||
'PhabricatorApplicationTransactionInterface',
|
||||
'PhabricatorFulltextInterface',
|
||||
|
|
|
@ -112,7 +112,7 @@ final class AuditQueryConduitAPIMethod extends AuditConduitAPIMethod {
|
|||
'id' => $request->getID(),
|
||||
'commitPHID' => $request->getCommitPHID(),
|
||||
'auditorPHID' => $request->getAuditorPHID(),
|
||||
'reasons' => $request->getAuditReasons(),
|
||||
'reasons' => array(),
|
||||
'status' => $request->getAuditStatus(),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -12,36 +12,4 @@ final class PhabricatorAuditActionConstants extends Phobject {
|
|||
const INLINE = 'audit:inline';
|
||||
const ACTION = 'audit:action';
|
||||
|
||||
public static function getActionNameMap() {
|
||||
$map = array(
|
||||
self::COMMENT => pht('Comment'),
|
||||
self::CONCERN => pht("Raise Concern \xE2\x9C\x98"),
|
||||
self::ACCEPT => pht("Accept Commit \xE2\x9C\x94"),
|
||||
self::RESIGN => pht('Resign from Audit'),
|
||||
self::CLOSE => pht('Close Audit'),
|
||||
self::ADD_CCS => pht('Add Subscribers'),
|
||||
self::ADD_AUDITORS => pht('Add Auditors'),
|
||||
);
|
||||
|
||||
return $map;
|
||||
}
|
||||
|
||||
public static function getActionName($constant) {
|
||||
$map = self::getActionNameMap();
|
||||
return idx($map, $constant, pht('Unknown'));
|
||||
}
|
||||
|
||||
public static function getActionPastTenseVerb($action) {
|
||||
$map = array(
|
||||
self::COMMENT => pht('commented on'),
|
||||
self::CONCERN => pht('raised a concern with'),
|
||||
self::ACCEPT => pht('accepted'),
|
||||
self::RESIGN => pht('resigned from'),
|
||||
self::CLOSE => pht('closed'),
|
||||
self::ADD_CCS => pht('added CCs to'),
|
||||
self::ADD_AUDITORS => pht('added auditors to'),
|
||||
);
|
||||
return idx($map, $action, pht('updated'));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ final class PhabricatorAuditEditor
|
|||
|
||||
const MAX_FILES_SHOWN_IN_EMAIL = 1000;
|
||||
|
||||
private $auditReasonMap = array();
|
||||
private $affectedFiles;
|
||||
private $rawPatch;
|
||||
private $auditorPHIDs = array();
|
||||
|
@ -13,26 +12,6 @@ final class PhabricatorAuditEditor
|
|||
private $didExpandInlineState = false;
|
||||
private $oldAuditStatus = null;
|
||||
|
||||
public function addAuditReason($phid, $reason) {
|
||||
if (!isset($this->auditReasonMap[$phid])) {
|
||||
$this->auditReasonMap[$phid] = array();
|
||||
}
|
||||
$this->auditReasonMap[$phid][] = $reason;
|
||||
return $this;
|
||||
}
|
||||
|
||||
private function getAuditReasons($phid) {
|
||||
if (isset($this->auditReasonMap[$phid])) {
|
||||
return $this->auditReasonMap[$phid];
|
||||
}
|
||||
if ($this->getIsHeraldEditor()) {
|
||||
$name = 'herald';
|
||||
} else {
|
||||
$name = $this->getActor()->getUsername();
|
||||
}
|
||||
return array(pht('Added by %s.', $name));
|
||||
}
|
||||
|
||||
public function setRawPatch($patch) {
|
||||
$this->rawPatch = $patch;
|
||||
return $this;
|
||||
|
@ -62,7 +41,6 @@ final class PhabricatorAuditEditor
|
|||
// TODO: These will get modernized eventually, but that can happen one
|
||||
// at a time later on.
|
||||
$types[] = PhabricatorAuditActionConstants::INLINE;
|
||||
$types[] = PhabricatorAuditActionConstants::ADD_AUDITORS;
|
||||
|
||||
return $types;
|
||||
}
|
||||
|
@ -107,10 +85,6 @@ final class PhabricatorAuditEditor
|
|||
case PhabricatorAuditActionConstants::INLINE:
|
||||
case PhabricatorAuditTransaction::TYPE_COMMIT:
|
||||
return null;
|
||||
case PhabricatorAuditActionConstants::ADD_AUDITORS:
|
||||
// TODO: For now, just record the added PHIDs. Eventually, turn these
|
||||
// into real edge transactions, probably?
|
||||
return array();
|
||||
}
|
||||
|
||||
return parent::getCustomTransactionOldValue($object, $xaction);
|
||||
|
@ -122,7 +96,6 @@ final class PhabricatorAuditEditor
|
|||
|
||||
switch ($xaction->getTransactionType()) {
|
||||
case PhabricatorAuditActionConstants::INLINE:
|
||||
case PhabricatorAuditActionConstants::ADD_AUDITORS:
|
||||
case PhabricatorAuditTransaction::TYPE_COMMIT:
|
||||
return $xaction->getNewValue();
|
||||
}
|
||||
|
@ -136,7 +109,6 @@ final class PhabricatorAuditEditor
|
|||
|
||||
switch ($xaction->getTransactionType()) {
|
||||
case PhabricatorAuditActionConstants::INLINE:
|
||||
case PhabricatorAuditActionConstants::ADD_AUDITORS:
|
||||
case PhabricatorAuditTransaction::TYPE_COMMIT:
|
||||
return;
|
||||
}
|
||||
|
@ -157,57 +129,6 @@ final class PhabricatorAuditEditor
|
|||
$reply->setHasReplies(1)->save();
|
||||
}
|
||||
return;
|
||||
case PhabricatorAuditActionConstants::ADD_AUDITORS:
|
||||
$new = $xaction->getNewValue();
|
||||
if (!is_array($new)) {
|
||||
$new = array();
|
||||
}
|
||||
|
||||
$old = $xaction->getOldValue();
|
||||
if (!is_array($old)) {
|
||||
$old = array();
|
||||
}
|
||||
|
||||
$add = array_diff_key($new, $old);
|
||||
|
||||
$actor = $this->requireActor();
|
||||
|
||||
$requests = $object->getAudits();
|
||||
$requests = mpull($requests, null, 'getAuditorPHID');
|
||||
foreach ($add as $phid) {
|
||||
if (isset($requests[$phid])) {
|
||||
$request = $requests[$phid];
|
||||
|
||||
// Only update an existing request if the current status is not
|
||||
// an interesting status.
|
||||
if ($request->isInteresting()) {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
$request = id(new PhabricatorRepositoryAuditRequest())
|
||||
->setCommitPHID($object->getPHID())
|
||||
->setAuditorPHID($phid);
|
||||
}
|
||||
|
||||
if ($this->getIsHeraldEditor()) {
|
||||
$audit_requested = $xaction->getMetadataValue('auditStatus');
|
||||
$audit_reason_map = $xaction->getMetadataValue('auditReasonMap');
|
||||
$audit_reason = $audit_reason_map[$phid];
|
||||
} else {
|
||||
$audit_requested = PhabricatorAuditStatusConstants::AUDIT_REQUESTED;
|
||||
$audit_reason = $this->getAuditReasons($phid);
|
||||
}
|
||||
|
||||
$request
|
||||
->setAuditStatus($audit_requested)
|
||||
->setAuditReasons($audit_reason)
|
||||
->save();
|
||||
|
||||
$requests[$phid] = $request;
|
||||
}
|
||||
|
||||
$object->attachAudits($requests);
|
||||
return;
|
||||
}
|
||||
|
||||
return parent::applyCustomExternalTransaction($object, $xaction);
|
||||
|
@ -375,35 +296,26 @@ final class PhabricatorAuditEditor
|
|||
private function createAuditRequestTransactionFromCommitMessage(
|
||||
PhabricatorRepositoryCommit $commit) {
|
||||
|
||||
$actor = $this->getActor();
|
||||
$data = $commit->getCommitData();
|
||||
$message = $data->getCommitMessage();
|
||||
|
||||
$matches = null;
|
||||
if (!preg_match('/^Auditors?:\s*(.*)$/im', $message, $matches)) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$phids = id(new PhabricatorObjectListQuery())
|
||||
->setViewer($this->getActor())
|
||||
->setAllowPartialResults(true)
|
||||
->setAllowedTypes(
|
||||
array(
|
||||
PhabricatorPeopleUserPHIDType::TYPECONST,
|
||||
PhabricatorProjectProjectPHIDType::TYPECONST,
|
||||
))
|
||||
->setObjectList($matches[1])
|
||||
->execute();
|
||||
$result = DifferentialCommitMessageParser::newStandardParser($actor)
|
||||
->setRaiseMissingFieldErrors(false)
|
||||
->parseFields($message);
|
||||
|
||||
$field_key = DifferentialAuditorsCommitMessageField::FIELDKEY;
|
||||
$phids = idx($result, $field_key, null);
|
||||
if (!$phids) {
|
||||
return array();
|
||||
}
|
||||
|
||||
foreach ($phids as $phid) {
|
||||
$this->addAuditReason($phid, pht('Requested by Author'));
|
||||
}
|
||||
return id(new PhabricatorAuditTransaction())
|
||||
->setTransactionType(PhabricatorAuditActionConstants::ADD_AUDITORS)
|
||||
->setNewValue(array_fuse($phids));
|
||||
return $commit->getApplicationTransactionTemplate()
|
||||
->setTransactionType(DiffusionCommitAuditorsTransaction::TRANSACTIONTYPE)
|
||||
->setNewValue(
|
||||
array(
|
||||
'+' => array_fuse($phids),
|
||||
));
|
||||
}
|
||||
|
||||
protected function sortTransactions(array $xactions) {
|
||||
|
|
|
@ -1,4 +1,90 @@
|
|||
<?php
|
||||
|
||||
abstract class PhabricatorAuditManagementWorkflow
|
||||
extends PhabricatorManagementWorkflow {}
|
||||
extends PhabricatorManagementWorkflow {
|
||||
|
||||
|
||||
protected function getCommitConstraintArguments() {
|
||||
return array(
|
||||
array(
|
||||
'name' => 'all',
|
||||
'help' => pht('Update all commits in all repositories.'),
|
||||
),
|
||||
array(
|
||||
'name' => 'objects',
|
||||
'wildcard' => true,
|
||||
'help' => pht('Update named commits and repositories.'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
protected function loadCommitsWithConstraints(PhutilArgumentParser $args) {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$all = $args->getArg('all');
|
||||
$names = $args->getArg('objects');
|
||||
|
||||
if (!$names && !$all) {
|
||||
throw new PhutilArgumentUsageException(
|
||||
pht(
|
||||
'Specify "--all" to affect everything, or a list of specific '.
|
||||
'commits or repositories to affect.'));
|
||||
} else if ($names && $all) {
|
||||
throw new PhutilArgumentUsageException(
|
||||
pht(
|
||||
'Specify either a list of objects to affect or "--all", but not '.
|
||||
'both.'));
|
||||
}
|
||||
|
||||
if ($all) {
|
||||
$objects = new LiskMigrationIterator(new PhabricatorRepository());
|
||||
} else {
|
||||
$query = id(new PhabricatorObjectQuery())
|
||||
->setViewer($viewer)
|
||||
->withNames($names);
|
||||
|
||||
$query->execute();
|
||||
|
||||
$objects = array();
|
||||
|
||||
$results = $query->getNamedResults();
|
||||
foreach ($names as $name) {
|
||||
if (!isset($results[$name])) {
|
||||
throw new PhutilArgumentUsageException(
|
||||
pht(
|
||||
'Object "%s" is not a valid object.',
|
||||
$name));
|
||||
}
|
||||
|
||||
$object = $results[$name];
|
||||
if (!($object instanceof PhabricatorRepository) &&
|
||||
!($object instanceof PhabricatorRepositoryCommit)) {
|
||||
throw new PhutilArgumentUsageException(
|
||||
pht(
|
||||
'Object "%s" is not a valid repository or commit.',
|
||||
$name));
|
||||
}
|
||||
|
||||
$objects[] = $object;
|
||||
}
|
||||
}
|
||||
|
||||
return $objects;
|
||||
}
|
||||
|
||||
protected function loadCommitsForConstraintObject($object) {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
if ($object instanceof PhabricatorRepository) {
|
||||
$commits = id(new DiffusionCommitQuery())
|
||||
->setViewer($viewer)
|
||||
->withRepository($object)
|
||||
->execute();
|
||||
} else {
|
||||
$commits = array($object);
|
||||
}
|
||||
|
||||
return $commits;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorAuditSynchronizeManagementWorkflow
|
||||
extends PhabricatorAuditManagementWorkflow {
|
||||
|
||||
protected function didConstruct() {
|
||||
$this
|
||||
->setName('synchronize')
|
||||
->setExamples('**synchronize** ...')
|
||||
->setSynopsis(pht('Update audit status for commits.'))
|
||||
->setArguments(
|
||||
array_merge(
|
||||
$this->getCommitConstraintArguments(),
|
||||
array()));
|
||||
}
|
||||
|
||||
public function execute(PhutilArgumentParser $args) {
|
||||
$viewer = $this->getViewer();
|
||||
$objects = $this->loadCommitsWithConstraints($args);
|
||||
|
||||
foreach ($objects as $object) {
|
||||
$commits = $this->loadCommitsForConstraintObject($object);
|
||||
foreach ($commits as $commit) {
|
||||
$commit = id(new DiffusionCommitQuery())
|
||||
->setViewer($viewer)
|
||||
->withPHIDs(array($commit->getPHID()))
|
||||
->needAuditRequests(true)
|
||||
->executeOne();
|
||||
if (!$commit) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$old_status = $commit->getAuditStatus();
|
||||
$commit->updateAuditStatus($commit->getAudits());
|
||||
$new_status = $commit->getAuditStatus();
|
||||
|
||||
if ($old_status == $new_status) {
|
||||
echo tsprintf(
|
||||
"%s\n",
|
||||
pht(
|
||||
'No changes for "%s".',
|
||||
$commit->getDisplayName()));
|
||||
} else {
|
||||
echo tsprintf(
|
||||
"%s\n",
|
||||
pht(
|
||||
'Updating "%s": "%s" -> "%s".',
|
||||
$commit->getDisplayName(),
|
||||
PhabricatorAuditCommitStatusConstants::getStatusName(
|
||||
$old_status),
|
||||
PhabricatorAuditCommitStatusConstants::getStatusName(
|
||||
$new_status)));
|
||||
|
||||
$commit->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorAuditUpdateOwnersManagementWorkflow
|
||||
extends PhabricatorAuditManagementWorkflow {
|
||||
|
||||
protected function didConstruct() {
|
||||
$this
|
||||
->setName('update-owners')
|
||||
->setExamples('**update-owners** ...')
|
||||
->setSynopsis(pht('Update package relationships for commits.'))
|
||||
->setArguments(
|
||||
array_merge(
|
||||
$this->getCommitConstraintArguments(),
|
||||
array()));
|
||||
}
|
||||
|
||||
public function execute(PhutilArgumentParser $args) {
|
||||
$viewer = $this->getViewer();
|
||||
$objects = $this->loadCommitsWithConstraints($args);
|
||||
|
||||
foreach ($objects as $object) {
|
||||
$commits = $this->loadCommitsForConstraintObject($object);
|
||||
|
||||
foreach ($commits as $commit) {
|
||||
$repository = $commit->getRepository();
|
||||
|
||||
$affected_paths = PhabricatorOwnerPathQuery::loadAffectedPaths(
|
||||
$repository,
|
||||
$commit,
|
||||
$viewer);
|
||||
|
||||
$affected_packages = PhabricatorOwnersPackage::loadAffectedPackages(
|
||||
$repository,
|
||||
$affected_paths);
|
||||
|
||||
$monograms = mpull($affected_packages, 'getMonogram');
|
||||
if ($monograms) {
|
||||
$monograms = implode(', ', $monograms);
|
||||
} else {
|
||||
$monograms = pht('none');
|
||||
}
|
||||
|
||||
echo tsprintf(
|
||||
"%s\n",
|
||||
pht(
|
||||
'Updating "%s" (%s)...',
|
||||
$commit->getDisplayName(),
|
||||
$monograms));
|
||||
|
||||
$commit->writeOwnersEdges(mpull($affected_packages, 'getPHID'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -45,6 +45,14 @@ final class PhabricatorCommitSearchEngine
|
|||
$query->withRepositoryPHIDs($map['repositoryPHIDs']);
|
||||
}
|
||||
|
||||
if ($map['packagePHIDs']) {
|
||||
$query->withPackagePHIDs($map['packagePHIDs']);
|
||||
}
|
||||
|
||||
if ($map['unreachable'] !== null) {
|
||||
$query->withUnreachable($map['unreachable']);
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
|
@ -78,6 +86,23 @@ final class PhabricatorCommitSearchEngine
|
|||
->setConduitKey('repositories')
|
||||
->setAliases(array('repository', 'repositories', 'repositoryPHID'))
|
||||
->setDatasource(new DiffusionRepositoryDatasource()),
|
||||
id(new PhabricatorSearchDatasourceField())
|
||||
->setLabel(pht('Packages'))
|
||||
->setKey('packagePHIDs')
|
||||
->setConduitKey('packages')
|
||||
->setAliases(array('package', 'packages', 'packagePHID'))
|
||||
->setDatasource(new PhabricatorOwnersPackageDatasource()),
|
||||
id(new PhabricatorSearchThreeStateField())
|
||||
->setLabel(pht('Unreachable'))
|
||||
->setKey('unreachable')
|
||||
->setOptions(
|
||||
pht('(Show All)'),
|
||||
pht('Show Only Unreachable Commits'),
|
||||
pht('Hide Unreachable Commits'))
|
||||
->setDescription(
|
||||
pht(
|
||||
'Find or exclude unreachable commits which are not ancestors of '.
|
||||
'any branch, tag, or ref.')),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -116,7 +141,8 @@ final class PhabricatorCommitSearchEngine
|
|||
$query
|
||||
->setParameter('responsiblePHIDs', array($viewer_phid))
|
||||
->setParameter('statuses', $open)
|
||||
->setParameter('bucket', $bucket_key);
|
||||
->setParameter('bucket', $bucket_key)
|
||||
->setParameter('unreachable', false);
|
||||
return $query;
|
||||
case 'authored':
|
||||
$query
|
||||
|
|
|
@ -140,6 +140,7 @@ final class PhabricatorAuditListView extends AphrontView {
|
|||
->setObjectName($commit_name)
|
||||
->setHeader($commit_desc)
|
||||
->setHref($commit_link)
|
||||
->setDisabled($commit->isUnreachable())
|
||||
->addByline(pht('Author: %s', $author_name))
|
||||
->addIcon('none', $committed);
|
||||
|
||||
|
|
|
@ -596,14 +596,18 @@ abstract class PhabricatorApplication
|
|||
protected function getProfileMenuRouting($controller) {
|
||||
$edit_route = $this->getEditRoutePattern();
|
||||
|
||||
$mode_route = '(?P<itemEditMode>global|custom)/';
|
||||
|
||||
return array(
|
||||
'(?P<itemAction>view)/(?P<itemID>[^/]+)/' => $controller,
|
||||
'(?P<itemAction>hide)/(?P<itemID>[^/]+)/' => $controller,
|
||||
'(?P<itemAction>default)/(?P<itemID>[^/]+)/' => $controller,
|
||||
'(?P<itemAction>configure)/' => $controller,
|
||||
'(?P<itemAction>reorder)/' => $controller,
|
||||
'(?P<itemAction>configure)/'.$mode_route => $controller,
|
||||
'(?P<itemAction>reorder)/'.$mode_route => $controller,
|
||||
'(?P<itemAction>edit)/'.$edit_route => $controller,
|
||||
'(?P<itemAction>new)/(?<itemKey>[^/]+)/'.$edit_route => $controller,
|
||||
'(?P<itemAction>new)/'.$mode_route.'(?<itemKey>[^/]+)/'.$edit_route
|
||||
=> $controller,
|
||||
'(?P<itemAction>builtin)/(?<itemID>[^/]+)/'.$edit_route
|
||||
=> $controller,
|
||||
);
|
||||
|
|
|
@ -209,10 +209,7 @@ final class CelerityDefaultPostprocessor
|
|||
'menu.profile.icon.disabled' => 'rgba(255,255,255,.4)',
|
||||
|
||||
'menu.main.height' => '44px',
|
||||
|
||||
'menu.profile.width' => '240px',
|
||||
'menu.profile.width.collapsed' => '88px',
|
||||
'menu.profile.item.height' => '46px',
|
||||
|
||||
);
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ final class PhabricatorRecaptchaConfigOptions
|
|||
|
||||
return array(
|
||||
$this->newOption('recaptcha.enabled', 'bool', false)
|
||||
->setLocked(true)
|
||||
->setBoolOptions(
|
||||
array(
|
||||
pht('Enable Recaptcha'),
|
||||
|
@ -35,6 +36,7 @@ final class PhabricatorRecaptchaConfigOptions
|
|||
'failed login attempts. This hinders brute-force attacks against '.
|
||||
'user passwords. For more information, see http://recaptcha.net/')),
|
||||
$this->newOption('recaptcha.public-key', 'string', null)
|
||||
->setLocked(true)
|
||||
->setDescription(
|
||||
pht('Recaptcha public key, obtained by signing up for Recaptcha.')),
|
||||
$this->newOption('recaptcha.private-key', 'string', null)
|
||||
|
|
|
@ -30,7 +30,6 @@ final class PhabricatorDashboardApplication extends PhabricatorApplication {
|
|||
'create/' => 'PhabricatorDashboardEditController',
|
||||
'copy/(?:(?P<id>\d+)/)?' => 'PhabricatorDashboardCopyController',
|
||||
'edit/(?:(?P<id>\d+)/)?' => 'PhabricatorDashboardEditController',
|
||||
'install/(?P<id>\d+)/' => 'PhabricatorDashboardInstallController',
|
||||
'uninstall/(?P<id>\d+)/' => 'PhabricatorDashboardUninstallController',
|
||||
'addpanel/(?P<id>\d+)/' => 'PhabricatorDashboardAddPanelController',
|
||||
'movepanel/(?P<id>\d+)/' => 'PhabricatorDashboardMovePanelController',
|
||||
|
|
|
@ -245,7 +245,7 @@ final class PhabricatorDashboardEditController
|
|||
|
||||
switch ($template) {
|
||||
case 'simple':
|
||||
$v_name = pht('New Simple Dashboard');
|
||||
$v_name = pht("%s's Dashboard", $viewer->getUsername());
|
||||
|
||||
$welcome_panel = $this->newPanel(
|
||||
$request,
|
||||
|
@ -260,8 +260,9 @@ final class PhabricatorDashboardEditController
|
|||
"rustic, authentic feel.\n\n".
|
||||
"You can drag, remove, add, and edit panels to customize the ".
|
||||
"rest of this dashboard to show the information you want.\n\n".
|
||||
"To install this dashboard on the home page, use the ".
|
||||
"**Install Dashboard** action link above."),
|
||||
"To install this dashboard on the home page, edit your personal ".
|
||||
"or global menu on the homepage and click Dashboard under ".
|
||||
"New Menu Item on the right."),
|
||||
));
|
||||
$panel_phids[] = $welcome_panel->getPHID();
|
||||
|
||||
|
@ -276,14 +277,25 @@ final class PhabricatorDashboardEditController
|
|||
));
|
||||
$panel_phids[] = $feed_panel->getPHID();
|
||||
|
||||
$revision_panel = $this->newPanel(
|
||||
$request,
|
||||
$viewer,
|
||||
'query',
|
||||
pht('Active Revisions'),
|
||||
array(
|
||||
'class' => 'DifferentialRevisionSearchEngine',
|
||||
'key' => 'active',
|
||||
));
|
||||
$panel_phids[] = $revision_panel->getPHID();
|
||||
|
||||
$task_panel = $this->newPanel(
|
||||
$request,
|
||||
$viewer,
|
||||
'query',
|
||||
pht('Open Tasks'),
|
||||
pht('Assigned Tasks'),
|
||||
array(
|
||||
'class' => 'ManiphestTaskSearchEngine',
|
||||
'key' => 'open',
|
||||
'key' => 'assigned',
|
||||
));
|
||||
$panel_phids[] = $task_panel->getPHID();
|
||||
|
||||
|
@ -302,6 +314,7 @@ final class PhabricatorDashboardEditController
|
|||
$layout = id(new PhabricatorDashboardLayoutConfig())
|
||||
->setLayoutMode($mode_2_and_1)
|
||||
->setPanelLocation(0, $welcome_panel->getPHID())
|
||||
->setPanelLocation(0, $revision_panel->getPHID())
|
||||
->setPanelLocation(0, $task_panel->getPHID())
|
||||
->setPanelLocation(0, $commit_panel->getPHID())
|
||||
->setPanelLocation(1, $feed_panel->getPHID());
|
||||
|
|
|
@ -1,148 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorDashboardInstallController
|
||||
extends PhabricatorDashboardController {
|
||||
|
||||
private $id;
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$viewer = $request->getViewer();
|
||||
$this->id = $request->getURIData('id');
|
||||
|
||||
$dashboard = id(new PhabricatorDashboardQuery())
|
||||
->setViewer($viewer)
|
||||
->withIDs(array($this->id))
|
||||
->executeOne();
|
||||
if (!$dashboard) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
$dashboard_phid = $dashboard->getPHID();
|
||||
|
||||
$object_phid = $request->getStr('objectPHID', $viewer->getPHID());
|
||||
switch ($object_phid) {
|
||||
case PhabricatorHomeApplication::DASHBOARD_DEFAULT:
|
||||
if (!$viewer->getIsAdmin()) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
$object = id(new PhabricatorObjectQuery())
|
||||
->setViewer($viewer)
|
||||
->requireCapabilities(
|
||||
array(
|
||||
PhabricatorPolicyCapability::CAN_VIEW,
|
||||
PhabricatorPolicyCapability::CAN_EDIT,
|
||||
))
|
||||
->withPHIDs(array($object_phid))
|
||||
->executeOne();
|
||||
if (!$object) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
$installer_phid = $viewer->getPHID();
|
||||
$application_class = $request->getStr(
|
||||
'applicationClass',
|
||||
'PhabricatorHomeApplication');
|
||||
|
||||
if ($request->isFormPost()) {
|
||||
$dashboard_install = id(new PhabricatorDashboardInstall())
|
||||
->loadOneWhere(
|
||||
'objectPHID = %s AND applicationClass = %s',
|
||||
$object_phid,
|
||||
$application_class);
|
||||
if (!$dashboard_install) {
|
||||
$dashboard_install = id(new PhabricatorDashboardInstall())
|
||||
->setObjectPHID($object_phid)
|
||||
->setApplicationClass($application_class);
|
||||
}
|
||||
$dashboard_install
|
||||
->setInstallerPHID($installer_phid)
|
||||
->setDashboardPHID($dashboard_phid)
|
||||
->save();
|
||||
return id(new AphrontRedirectResponse())
|
||||
->setURI($this->getRedirectURI($application_class, $object_phid));
|
||||
}
|
||||
|
||||
$dialog = $this->newDialog()
|
||||
->setTitle(pht('Install Dashboard'))
|
||||
->addHiddenInput('objectPHID', $object_phid)
|
||||
->addCancelButton($this->getCancelURI($application_class, $object_phid))
|
||||
->addSubmitButton(pht('Install Dashboard'));
|
||||
|
||||
switch ($application_class) {
|
||||
case 'PhabricatorHomeApplication':
|
||||
if ($viewer->getPHID() == $object_phid) {
|
||||
if ($viewer->getIsAdmin()) {
|
||||
$dialog->setWidth(AphrontDialogView::WIDTH_FORM);
|
||||
|
||||
$form = id(new AphrontFormView())
|
||||
->setUser($viewer)
|
||||
->appendRemarkupInstructions(
|
||||
pht('Choose where to install this dashboard.'))
|
||||
->appendChild(
|
||||
id(new AphrontFormRadioButtonControl())
|
||||
->setName('objectPHID')
|
||||
->setValue(PhabricatorHomeApplication::DASHBOARD_DEFAULT)
|
||||
->addButton(
|
||||
PhabricatorHomeApplication::DASHBOARD_DEFAULT,
|
||||
pht('Default Dashboard for All Users'),
|
||||
pht(
|
||||
'Install this dashboard as the global default dashboard '.
|
||||
'for all users. Users can install a personal dashboard '.
|
||||
'to replace it. All users who have not configured '.
|
||||
'a personal dashboard will be affected by this change.'))
|
||||
->addButton(
|
||||
$viewer->getPHID(),
|
||||
pht('Personal Home Page Dashboard'),
|
||||
pht(
|
||||
'Install this dashboard as your personal home page '.
|
||||
'dashboard. Only you will be affected by this change.')));
|
||||
|
||||
$dialog->appendChild($form->buildLayoutView());
|
||||
} else {
|
||||
$dialog->appendParagraph(
|
||||
pht('Install this dashboard on your home page?'));
|
||||
}
|
||||
} else {
|
||||
$dialog->appendParagraph(
|
||||
pht(
|
||||
'Install this dashboard as the home page dashboard for %s?',
|
||||
phutil_tag(
|
||||
'strong',
|
||||
array(),
|
||||
$viewer->renderHandle($object_phid))));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Unknown dashboard application class "%s"!',
|
||||
$application_class));
|
||||
}
|
||||
|
||||
return $dialog;
|
||||
}
|
||||
|
||||
private function getCancelURI($application_class, $object_phid) {
|
||||
$uri = null;
|
||||
switch ($application_class) {
|
||||
case 'PhabricatorHomeApplication':
|
||||
$uri = '/dashboard/view/'.$this->id.'/';
|
||||
break;
|
||||
}
|
||||
return $uri;
|
||||
}
|
||||
|
||||
private function getRedirectURI($application_class, $object_phid) {
|
||||
$uri = null;
|
||||
switch ($application_class) {
|
||||
case 'PhabricatorHomeApplication':
|
||||
$uri = '/';
|
||||
break;
|
||||
}
|
||||
return $uri;
|
||||
}
|
||||
|
||||
}
|
|
@ -156,26 +156,6 @@ final class PhabricatorDashboardManageController
|
|||
->setHref($this->getApplicationURI("copy/{$id}/"))
|
||||
->setWorkflow(true));
|
||||
|
||||
$installed_dashboard = id(new PhabricatorDashboardInstall())
|
||||
->loadOneWhere(
|
||||
'objectPHID = %s AND applicationClass = %s',
|
||||
$viewer->getPHID(),
|
||||
'PhabricatorHomeApplication');
|
||||
if ($installed_dashboard &&
|
||||
$installed_dashboard->getDashboardPHID() == $dashboard->getPHID()) {
|
||||
$title_install = pht('Uninstall Dashboard');
|
||||
$href_install = "uninstall/{$id}/";
|
||||
} else {
|
||||
$title_install = pht('Install Dashboard');
|
||||
$href_install = "install/{$id}/";
|
||||
}
|
||||
$curtain->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setName($title_install)
|
||||
->setIcon('fa-wrench')
|
||||
->setHref($this->getApplicationURI($href_install))
|
||||
->setWorkflow(true));
|
||||
|
||||
return $curtain;
|
||||
}
|
||||
|
||||
|
|
|
@ -72,8 +72,10 @@ final class PhabricatorDashboardPanelRenderingEngine extends Phobject {
|
|||
|
||||
if (!$panel) {
|
||||
return $this->renderErrorPanel(
|
||||
pht('Missing Panel'),
|
||||
pht('This panel does not exist.'));
|
||||
pht('Missing or Restricted Panel'),
|
||||
pht(
|
||||
'This panel does not exist, or you do not have permission '.
|
||||
'to see it.'));
|
||||
}
|
||||
|
||||
$panel_type = $panel->getImplementation();
|
||||
|
@ -166,10 +168,13 @@ final class PhabricatorDashboardPanelRenderingEngine extends Phobject {
|
|||
}
|
||||
$icon = id(new PHUIIconView())
|
||||
->setIcon('fa-warning red msr');
|
||||
|
||||
$content = id(new PHUIBoxView())
|
||||
->addClass('dashboard-box')
|
||||
->addMargin(PHUI::MARGIN_MEDIUM)
|
||||
->appendChild($icon)
|
||||
->appendChild($body);
|
||||
|
||||
return $this->renderPanelDiv(
|
||||
$content,
|
||||
$header);
|
||||
|
@ -203,10 +208,17 @@ final class PhabricatorDashboardPanelRenderingEngine extends Phobject {
|
|||
$box->appendChild($content);
|
||||
}
|
||||
|
||||
$box->setHeader($header)
|
||||
$box
|
||||
->setHeader($header)
|
||||
->setID($id)
|
||||
->addSigil('dashboard-panel')
|
||||
->setMetadata(array('objectPHID' => $panel->getPHID()));
|
||||
->addSigil('dashboard-panel');
|
||||
|
||||
if ($panel) {
|
||||
$box->setMetadata(
|
||||
array(
|
||||
'objectPHID' => $panel->getPHID(),
|
||||
));
|
||||
}
|
||||
|
||||
return phutil_tag_div('dashboard-pane', $box);
|
||||
}
|
||||
|
@ -243,6 +255,10 @@ final class PhabricatorDashboardPanelRenderingEngine extends Phobject {
|
|||
PHUIHeaderView $header) {
|
||||
$panel = $this->getPanel();
|
||||
|
||||
if (!$panel) {
|
||||
return $header;
|
||||
}
|
||||
|
||||
$dashboard_id = $this->getDashboardID();
|
||||
$edit_uri = id(new PhutilURI(
|
||||
'/dashboard/panel/edit/'.$panel->getID().'/'));
|
||||
|
|
|
@ -32,7 +32,7 @@ final class PhabricatorDashboardRenderingEngine extends Phobject {
|
|||
$dashboard_id = celerity_generate_unique_node_id();
|
||||
$result = id(new AphrontMultiColumnView())
|
||||
->setID($dashboard_id)
|
||||
->setFluidlayout(true)
|
||||
->setFluidLayout(true)
|
||||
->setGutter(AphrontMultiColumnView::GUTTER_LARGE);
|
||||
|
||||
if ($this->arrangeMode) {
|
||||
|
@ -43,17 +43,27 @@ final class PhabricatorDashboardRenderingEngine extends Phobject {
|
|||
|
||||
foreach ($panel_grid_locations as $column => $panel_column_locations) {
|
||||
$panel_phids = $panel_column_locations;
|
||||
$column_panels = array_select_keys($panels, $panel_phids);
|
||||
|
||||
// TODO: This list may contain duplicates when the dashboard itself
|
||||
// does not? Perhaps this is related to T10612. For now, just unique
|
||||
// the list before moving on.
|
||||
$panel_phids = array_unique($panel_phids);
|
||||
|
||||
$column_result = array();
|
||||
foreach ($column_panels as $panel) {
|
||||
$column_result[] = id(new PhabricatorDashboardPanelRenderingEngine())
|
||||
foreach ($panel_phids as $panel_phid) {
|
||||
$panel_engine = id(new PhabricatorDashboardPanelRenderingEngine())
|
||||
->setViewer($viewer)
|
||||
->setPanel($panel)
|
||||
->setDashboardID($dashboard->getID())
|
||||
->setEnableAsyncRendering(true)
|
||||
->setParentPanelPHIDs(array())
|
||||
->setHeaderMode($h_mode)
|
||||
->renderPanel();
|
||||
->setHeaderMode($h_mode);
|
||||
|
||||
$panel = idx($panels, $panel_phid);
|
||||
if ($panel) {
|
||||
$panel_engine->setPanel($panel);
|
||||
}
|
||||
|
||||
$column_result[] = $panel_engine->renderPanel();
|
||||
}
|
||||
$column_class = $layout_config->getColumnClass(
|
||||
$column,
|
||||
|
|
|
@ -70,8 +70,13 @@ final class PhabricatorDashboardQuery
|
|||
|
||||
$panel_phids = $edge_query->getDestinationPHIDs();
|
||||
if ($panel_phids) {
|
||||
// NOTE: We explicitly disable policy exceptions when loading panels.
|
||||
// If a particular panel is invalid or not visible to the viewer,
|
||||
// we'll still render the dashboard, just not that panel.
|
||||
|
||||
$panels = id(new PhabricatorDashboardPanelQuery())
|
||||
->setParentQuery($this)
|
||||
->setRaisePolicyExceptions(false)
|
||||
->setViewer($this->getViewer())
|
||||
->withPHIDs($panel_phids)
|
||||
->execute();
|
||||
|
|
|
@ -443,7 +443,7 @@ final class DifferentialRevisionViewController extends DifferentialController {
|
|||
$operations_box = $this->buildOperationsBox($revision);
|
||||
|
||||
$crumbs = $this->buildApplicationCrumbs();
|
||||
$crumbs->addTextCrumb($monogram, $revision->getURI());
|
||||
$crumbs->addTextCrumb($monogram);
|
||||
$crumbs->setBorder(true);
|
||||
|
||||
$filetree_on = $viewer->compareUserSetting(
|
||||
|
|
|
@ -9,12 +9,19 @@ final class DifferentialAuditorsCommitMessageField
|
|||
return pht('Auditors');
|
||||
}
|
||||
|
||||
public function getFieldAliases() {
|
||||
return array(
|
||||
'Auditor',
|
||||
);
|
||||
}
|
||||
|
||||
public function parseFieldValue($value) {
|
||||
return $this->parseObjectList(
|
||||
$value,
|
||||
array(
|
||||
PhabricatorPeopleUserPHIDType::TYPECONST,
|
||||
PhabricatorProjectProjectPHIDType::TYPECONST,
|
||||
PhabricatorOwnersPackagePHIDType::TYPECONST,
|
||||
));
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ final class DifferentialDiff
|
|||
PhabricatorExtendedPolicyInterface,
|
||||
HarbormasterBuildableInterface,
|
||||
HarbormasterCircleCIBuildableInterface,
|
||||
HarbormasterBuildkiteBuildableInterface,
|
||||
PhabricatorApplicationTransactionInterface,
|
||||
PhabricatorDestructibleInterface {
|
||||
|
||||
|
@ -621,6 +622,27 @@ final class DifferentialDiff
|
|||
return $ref;
|
||||
}
|
||||
|
||||
|
||||
/* -( HarbormasterBuildkiteBuildableInterface )---------------------------- */
|
||||
|
||||
public function getBuildkiteBranch() {
|
||||
$ref = $this->getStagingRef();
|
||||
|
||||
// NOTE: Circa late January 2017, Buildkite fails with the error message
|
||||
// "Tags have been disabled for this project" if we pass the "refs/tags/"
|
||||
// prefix via the API and the project doesn't have GitHub tag builds
|
||||
// enabled, even if GitHub builds are disabled. The tag builds fine
|
||||
// without this prefix.
|
||||
$ref = preg_replace('(^refs/tags/)', '', $ref);
|
||||
|
||||
return $ref;
|
||||
}
|
||||
|
||||
public function getBuildkiteCommit() {
|
||||
return 'HEAD';
|
||||
}
|
||||
|
||||
|
||||
public function getStagingRef() {
|
||||
// TODO: We're just hoping to get lucky. Instead, `arc` should store
|
||||
// where it sent changes and we should only provide staging details
|
||||
|
|
|
@ -41,7 +41,7 @@ final class DifferentialRevisionCommandeerTransaction
|
|||
}
|
||||
|
||||
public function getCommandSummary() {
|
||||
return pht('Commadeer a revision.');
|
||||
return pht('Commandeer a revision.');
|
||||
}
|
||||
|
||||
public function generateOldValue($object) {
|
||||
|
|
|
@ -855,12 +855,6 @@ final class DiffusionCommitController extends DiffusionController {
|
|||
PhabricatorAuditStatusConstants::getStatusColor($code),
|
||||
PhabricatorAuditStatusConstants::getStatusName($code));
|
||||
|
||||
$note = array();
|
||||
foreach ($request->getAuditReasons() as $reason) {
|
||||
$note[] = phutil_tag('div', array(), $reason);
|
||||
}
|
||||
$item->setNote($note);
|
||||
|
||||
$auditor_phid = $request->getAuditorPHID();
|
||||
$target = $viewer->renderHandle($auditor_phid);
|
||||
$item->setTarget($target);
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
<?php
|
||||
|
||||
final class DiffusionCommitHasPackageEdgeType
|
||||
extends PhabricatorEdgeType {
|
||||
|
||||
const EDGECONST = 65;
|
||||
|
||||
}
|
|
@ -39,19 +39,12 @@ abstract class DiffusionAuditorsHeraldAction
|
|||
|
||||
$phids = array_fuse(array_keys($targets));
|
||||
|
||||
// TODO: Convert this to be translatable, structured data eventually.
|
||||
$reason_map = array();
|
||||
foreach ($phids as $phid) {
|
||||
$reason_map[$phid][] = pht('%s Triggered Audit', $rule->getMonogram());
|
||||
}
|
||||
|
||||
$xaction = $adapter->newTransaction()
|
||||
->setTransactionType(PhabricatorAuditActionConstants::ADD_AUDITORS)
|
||||
->setNewValue($phids)
|
||||
->setMetadataValue(
|
||||
'auditStatus',
|
||||
PhabricatorAuditStatusConstants::AUDIT_REQUIRED)
|
||||
->setMetadataValue('auditReasonMap', $reason_map);
|
||||
->setTransactionType(DiffusionCommitAuditorsTransaction::TRANSACTIONTYPE)
|
||||
->setNewValue(
|
||||
array(
|
||||
'+' => $phids,
|
||||
));
|
||||
|
||||
$adapter->queueTransaction($xaction);
|
||||
|
||||
|
|
|
@ -13,6 +13,8 @@ final class DiffusionCommitQuery
|
|||
private $identifierMap;
|
||||
private $responsiblePHIDs;
|
||||
private $statuses;
|
||||
private $packagePHIDs;
|
||||
private $unreachable;
|
||||
|
||||
private $needAuditRequests;
|
||||
private $auditIDs;
|
||||
|
@ -124,17 +126,19 @@ final class DiffusionCommitQuery
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function withStatuses(array $statuses) {
|
||||
$this->statuses = $statuses;
|
||||
public function withPackagePHIDs(array $package_phids) {
|
||||
$this->packagePHIDs = $package_phids;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withAuditStatus($status) {
|
||||
// TODO: Replace callers with `withStatuses()`.
|
||||
return $this->withStatuses(
|
||||
array(
|
||||
$status,
|
||||
));
|
||||
public function withUnreachable($unreachable) {
|
||||
$this->unreachable = $unreachable;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withStatuses(array $statuses) {
|
||||
$this->statuses = $statuses;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withEpochRange($min, $max) {
|
||||
|
@ -498,6 +502,28 @@ final class DiffusionCommitQuery
|
|||
$this->statuses);
|
||||
}
|
||||
|
||||
if ($this->packagePHIDs !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'package.dst IN (%Ls)',
|
||||
$this->packagePHIDs);
|
||||
}
|
||||
|
||||
if ($this->unreachable !== null) {
|
||||
if ($this->unreachable) {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'(commit.importStatus & %d) = %d',
|
||||
PhabricatorRepositoryCommit::IMPORTED_UNREACHABLE,
|
||||
PhabricatorRepositoryCommit::IMPORTED_UNREACHABLE);
|
||||
} else {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'(commit.importStatus & %d) = 0',
|
||||
PhabricatorRepositoryCommit::IMPORTED_UNREACHABLE);
|
||||
}
|
||||
}
|
||||
|
||||
return $where;
|
||||
}
|
||||
|
||||
|
@ -519,6 +545,10 @@ final class DiffusionCommitQuery
|
|||
return (bool)$this->responsiblePHIDs;
|
||||
}
|
||||
|
||||
private function shouldJoinOwners() {
|
||||
return (bool)$this->packagePHIDs;
|
||||
}
|
||||
|
||||
protected function buildJoinClauseParts(AphrontDatabaseConnection $conn) {
|
||||
$join = parent::buildJoinClauseParts($conn);
|
||||
$audit_request = new PhabricatorRepositoryAuditRequest();
|
||||
|
@ -537,6 +567,15 @@ final class DiffusionCommitQuery
|
|||
$audit_request->getTableName());
|
||||
}
|
||||
|
||||
if ($this->shouldJoinOwners()) {
|
||||
$join[] = qsprintf(
|
||||
$conn,
|
||||
'JOIN %T package ON commit.phid = package.src
|
||||
AND package.type = %s',
|
||||
PhabricatorEdgeConfig::TABLE_NAME_EDGE,
|
||||
DiffusionCommitHasPackageEdgeType::EDGECONST);
|
||||
}
|
||||
|
||||
return $join;
|
||||
}
|
||||
|
||||
|
@ -549,6 +588,10 @@ final class DiffusionCommitQuery
|
|||
return true;
|
||||
}
|
||||
|
||||
if ($this->shouldJoinOwners()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return parent::shouldGroupQueryResultRows();
|
||||
}
|
||||
|
||||
|
|
|
@ -128,6 +128,10 @@ final class DiffusionCommitRequiredActionResultBucket
|
|||
$should_audit = array_fuse($should_audit);
|
||||
|
||||
foreach ($objects as $key => $object) {
|
||||
if (isset($phids[$object->getAuthorPHID()])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$this->hasAuditorsWithStatus($object, $phids, $should_audit)) {
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -178,7 +178,10 @@ final class DiffusionLowLevelResolveRefsQuery
|
|||
// repositories with a huge number of tags.
|
||||
$tag_refs = id(new DiffusionLowLevelGitRefQuery())
|
||||
->setRepository($repository)
|
||||
->withIsTag(true)
|
||||
->withRefTypes(
|
||||
array(
|
||||
PhabricatorRepositoryRefCursor::TYPE_TAG,
|
||||
))
|
||||
->executeQuery();
|
||||
foreach ($tag_refs as $tag_ref) {
|
||||
$tag_map[$tag_ref->getShortName()] = $tag_ref->getCommitIdentifier();
|
||||
|
|
|
@ -21,8 +21,7 @@ final class PhabricatorFavoritesApplication extends PhabricatorApplication {
|
|||
public function getRoutes() {
|
||||
return array(
|
||||
'/favorites/' => array(
|
||||
'' => 'PhabricatorFavoritesMainController',
|
||||
'(?P<type>global|personal)/item/' => $this->getProfileMenuRouting(
|
||||
'menu/' => $this->getProfileMenuRouting(
|
||||
'PhabricatorFavoritesMenuItemController'),
|
||||
),
|
||||
);
|
||||
|
|
|
@ -1,63 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorFavoritesMainController
|
||||
extends PhabricatorFavoritesController {
|
||||
|
||||
public function shouldAllowPublic() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$viewer = $request->getViewer();
|
||||
|
||||
if (!$viewer->getIsAdmin()) {
|
||||
$uri = '/favorites/personal/item/configure/';
|
||||
return id(new AphrontRedirectResponse())->setURI($uri);
|
||||
}
|
||||
|
||||
$menu = id(new PHUIObjectItemListView())
|
||||
->setUser($viewer);
|
||||
|
||||
$menu->addItem(
|
||||
id(new PHUIObjectItemView())
|
||||
->setHeader(pht('Personal Menu Items'))
|
||||
->setHref($this->getApplicationURI('personal/item/configure/'))
|
||||
->setImageURI($viewer->getProfileImageURI())
|
||||
->addAttribute(pht('Edit favorites for your personal account.')));
|
||||
|
||||
$icon = id(new PHUIIconView())
|
||||
->setIcon('fa-globe')
|
||||
->setBackground('bg-blue');
|
||||
|
||||
$menu->addItem(
|
||||
id(new PHUIObjectItemView())
|
||||
->setHeader(pht('Global Menu Items'))
|
||||
->setHref($this->getApplicationURI('global/item/configure/'))
|
||||
->setImageIcon($icon)
|
||||
->addAttribute(pht('Edit global default favorites for all users.')));
|
||||
|
||||
$crumbs = $this->buildApplicationCrumbs();
|
||||
$crumbs->addTextCrumb(pht('Manage'));
|
||||
$crumbs->setBorder(true);
|
||||
|
||||
$box = id(new PHUIObjectBoxView())
|
||||
->setObjectList($menu);
|
||||
|
||||
$header = id(new PHUIHeaderView())
|
||||
->setHeader(pht('Manage Favorites'))
|
||||
->setHeaderIcon('fa-star-o');
|
||||
|
||||
$view = id(new PHUITwoColumnView())
|
||||
->setHeader($header)
|
||||
->setFooter(array(
|
||||
$box,
|
||||
));
|
||||
|
||||
return $this->newPage()
|
||||
->setTitle(pht('Manage'))
|
||||
->setCrumbs($crumbs)
|
||||
->appendChild($view);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -5,13 +5,6 @@ final class PhabricatorFavoritesMenuItemController
|
|||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$viewer = $this->getViewer();
|
||||
$type = $request->getURIData('type');
|
||||
$custom_phid = null;
|
||||
$menu = PhabricatorProfileMenuEngine::MENU_GLOBAL;
|
||||
if ($type == 'personal') {
|
||||
$custom_phid = $viewer->getPHID();
|
||||
$menu = PhabricatorProfileMenuEngine::MENU_PERSONAL;
|
||||
}
|
||||
|
||||
$application = 'PhabricatorFavoritesApplication';
|
||||
$favorites = id(new PhabricatorApplicationQuery())
|
||||
|
@ -22,9 +15,8 @@ final class PhabricatorFavoritesMenuItemController
|
|||
|
||||
$engine = id(new PhabricatorFavoritesProfileMenuEngine())
|
||||
->setProfileObject($favorites)
|
||||
->setCustomPHID($custom_phid)
|
||||
->setCustomPHID($viewer->getPHID())
|
||||
->setController($this)
|
||||
->setMenuType($menu)
|
||||
->setShowNavigation(false);
|
||||
|
||||
return $engine->buildResponse();
|
||||
|
|
|
@ -8,14 +8,7 @@ final class PhabricatorFavoritesProfileMenuEngine
|
|||
}
|
||||
|
||||
public function getItemURI($path) {
|
||||
$object = $this->getProfileObject();
|
||||
$custom = $this->getCustomPHID();
|
||||
|
||||
if ($custom) {
|
||||
return "/favorites/personal/item/{$path}";
|
||||
} else {
|
||||
return "/favorites/global/item/{$path}";
|
||||
}
|
||||
return "/favorites/menu/{$path}";
|
||||
}
|
||||
|
||||
protected function getBuiltinProfileItems($object) {
|
||||
|
|
|
@ -50,16 +50,8 @@ final class PhabricatorFavoritesMainMenuBarExtension
|
|||
|
||||
$menu_engine = id(new PhabricatorFavoritesProfileMenuEngine())
|
||||
->setViewer($viewer)
|
||||
->setProfileObject($favorites);
|
||||
|
||||
if ($viewer->getPHID()) {
|
||||
$menu_engine
|
||||
->setCustomPHID($viewer->getPHID())
|
||||
->setMenuType(PhabricatorProfileMenuEngine::MENU_COMBINED);
|
||||
} else {
|
||||
$menu_engine
|
||||
->setMenuType(PhabricatorProfileMenuEngine::MENU_GLOBAL);
|
||||
}
|
||||
->setProfileObject($favorites)
|
||||
->setCustomPHID($viewer->getPHID());
|
||||
|
||||
$filter_view = $menu_engine->buildNavigation();
|
||||
|
||||
|
@ -69,14 +61,10 @@ final class PhabricatorFavoritesMainMenuBarExtension
|
|||
$view = id(new PhabricatorActionListView())
|
||||
->setViewer($viewer);
|
||||
foreach ($item_views as $item) {
|
||||
$type = null;
|
||||
if (!strlen($item->getName())) {
|
||||
$type = PhabricatorActionView::TYPE_DIVIDER;
|
||||
}
|
||||
$action = id(new PhabricatorActionView())
|
||||
->setName($item->getName())
|
||||
->setHref($item->getHref())
|
||||
->setType($type);
|
||||
->setType($item->getType());
|
||||
$view->addAction($action);
|
||||
}
|
||||
|
||||
|
@ -87,7 +75,7 @@ final class PhabricatorFavoritesMainMenuBarExtension
|
|||
$view->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setName(pht('Edit Favorites'))
|
||||
->setHref('/favorites/'));
|
||||
->setHref('/favorites/menu/configure/'));
|
||||
}
|
||||
|
||||
return $view;
|
||||
|
|
|
@ -58,9 +58,9 @@ final class PhabricatorFileThumbnailTransform
|
|||
public function generateTransforms() {
|
||||
return array(
|
||||
id(new PhabricatorFileThumbnailTransform())
|
||||
->setName(pht("Profile (200px \xC3\x97 200px)"))
|
||||
->setName(pht("Profile (400px \xC3\x97 400px)"))
|
||||
->setKey(self::TRANSFORM_PROFILE)
|
||||
->setDimensions(200, 200)
|
||||
->setDimensions(400, 400)
|
||||
->setScaleUp(true),
|
||||
id(new PhabricatorFileThumbnailTransform())
|
||||
->setName(pht("Pinboard (280px \xC3\x97 210px)"))
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorIconDatasource extends PhabricatorTypeaheadDatasource {
|
||||
|
||||
public function getPlaceholderText() {
|
||||
return pht('Type an icon name...');
|
||||
}
|
||||
|
||||
public function getBrowseTitle() {
|
||||
return pht('Browse Icons');
|
||||
}
|
||||
|
||||
public function getDatasourceApplicationClass() {
|
||||
return 'PhabricatorFilesApplication';
|
||||
}
|
||||
|
||||
public function loadResults() {
|
||||
$results = $this->buildResults();
|
||||
return $this->filterResultsAgainstTokens($results);
|
||||
}
|
||||
|
||||
protected function renderSpecialTokens(array $values) {
|
||||
return $this->renderTokensFromResults($this->buildResults(), $values);
|
||||
}
|
||||
|
||||
private function buildResults() {
|
||||
$raw_query = $this->getRawQuery();
|
||||
|
||||
$icons = id(new PHUIIconView())->getIcons();
|
||||
|
||||
$results = array();
|
||||
foreach ($icons as $icon) {
|
||||
$display_name = str_replace('fa-', '', $icon);
|
||||
$result = id(new PhabricatorTypeaheadResult())
|
||||
->setPHID($icon)
|
||||
->setName($icon)
|
||||
->setIcon($icon)
|
||||
->setDisplayname($display_name)
|
||||
->addAttribute($icon);
|
||||
|
||||
$results[$icon] = $result;
|
||||
}
|
||||
return $results;
|
||||
}
|
||||
|
||||
}
|
|
@ -94,6 +94,7 @@ final class PhabricatorHarbormasterApplication extends PhabricatorApplication {
|
|||
),
|
||||
'hook/' => array(
|
||||
'circleci/' => 'HarbormasterCircleCIHookController',
|
||||
'buildkite/' => 'HarbormasterBuildkiteHookController',
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
|
@ -0,0 +1,111 @@
|
|||
<?php
|
||||
|
||||
final class HarbormasterBuildkiteHookController
|
||||
extends HarbormasterController {
|
||||
|
||||
public function shouldRequireLogin() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @phutil-external-symbol class PhabricatorStartup
|
||||
*/
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$raw_body = PhabricatorStartup::getRawInput();
|
||||
$body = phutil_json_decode($raw_body);
|
||||
|
||||
$event = idx($body, 'event');
|
||||
if ($event != 'build.finished') {
|
||||
return $this->newHookResponse(pht('OK: Ignored event.'));
|
||||
}
|
||||
|
||||
$build = idx($body, 'build');
|
||||
if (!is_array($build)) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Expected "%s" property to contain a dictionary.',
|
||||
'build'));
|
||||
}
|
||||
|
||||
$meta_data = idx($build, 'meta_data');
|
||||
if (!is_array($meta_data)) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Expected "%s" property to contain a dictionary.',
|
||||
'build.meta_data'));
|
||||
}
|
||||
|
||||
$target_phid = idx($meta_data, 'buildTargetPHID');
|
||||
if (!$target_phid) {
|
||||
return $this->newHookResponse(pht('OK: No Harbormaster target PHID.'));
|
||||
}
|
||||
|
||||
$viewer = PhabricatorUser::getOmnipotentUser();
|
||||
$target = id(new HarbormasterBuildTargetQuery())
|
||||
->setViewer($viewer)
|
||||
->withPHIDs(array($target_phid))
|
||||
->needBuildSteps(true)
|
||||
->executeOne();
|
||||
if (!$target) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Harbormaster build target "%s" does not exist.',
|
||||
$target_phid));
|
||||
}
|
||||
|
||||
$step = $target->getBuildStep();
|
||||
$impl = $step->getStepImplementation();
|
||||
if (!($impl instanceof HarbormasterBuildkiteBuildStepImplementation)) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Harbormaster build target "%s" is not a Buildkite build step. '.
|
||||
'Only Buildkite steps may be updated via the Buildkite hook.',
|
||||
$target_phid));
|
||||
}
|
||||
|
||||
$webhook_token = $impl->getSetting('webhook.token');
|
||||
$request_token = $request->getHTTPHeader('X-Buildkite-Token');
|
||||
|
||||
if (!phutil_hashes_are_identical($webhook_token, $request_token)) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Buildkite request to target "%s" had the wrong authentication '.
|
||||
'token. The Buildkite pipeline and Harbormaster build step must '.
|
||||
'be configured with the same token.',
|
||||
$target_phid));
|
||||
}
|
||||
|
||||
$state = idx($build, 'state');
|
||||
switch ($state) {
|
||||
case 'passed':
|
||||
$message_type = HarbormasterMessageType::MESSAGE_PASS;
|
||||
break;
|
||||
default:
|
||||
$message_type = HarbormasterMessageType::MESSAGE_FAIL;
|
||||
break;
|
||||
}
|
||||
|
||||
$api_method = 'harbormaster.sendmessage';
|
||||
$api_params = array(
|
||||
'buildTargetPHID' => $target_phid,
|
||||
'type' => $message_type,
|
||||
);
|
||||
|
||||
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
|
||||
|
||||
id(new ConduitCall($api_method, $api_params))
|
||||
->setUser($viewer)
|
||||
->execute();
|
||||
|
||||
unset($unguarded);
|
||||
|
||||
return $this->newHookResponse(pht('OK: Processed event.'));
|
||||
}
|
||||
|
||||
private function newHookResponse($message) {
|
||||
$response = new AphrontWebpageResponse();
|
||||
$response->setContent($message);
|
||||
return $response;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Support for Buildkite.
|
||||
*/
|
||||
interface HarbormasterBuildkiteBuildableInterface {
|
||||
|
||||
public function getBuildkiteBranch();
|
||||
public function getBuildkiteCommit();
|
||||
|
||||
}
|
|
@ -0,0 +1,210 @@
|
|||
<?php
|
||||
|
||||
final class HarbormasterBuildkiteBuildStepImplementation
|
||||
extends HarbormasterBuildStepImplementation {
|
||||
|
||||
public function getName() {
|
||||
return pht('Build with Buildkite');
|
||||
}
|
||||
|
||||
public function getGenericDescription() {
|
||||
return pht('Trigger a build in Buildkite.');
|
||||
}
|
||||
|
||||
public function getBuildStepGroupKey() {
|
||||
return HarbormasterExternalBuildStepGroup::GROUPKEY;
|
||||
}
|
||||
|
||||
public function getDescription() {
|
||||
return pht('Run a build in Buildkite.');
|
||||
}
|
||||
|
||||
public function getEditInstructions() {
|
||||
$hook_uri = '/harbormaster/hook/buildkite/';
|
||||
$hook_uri = PhabricatorEnv::getProductionURI($hook_uri);
|
||||
|
||||
return pht(<<<EOTEXT
|
||||
WARNING: This build step is new and experimental!
|
||||
|
||||
To build **revisions** with Buildkite, they must:
|
||||
|
||||
- belong to a tracked repository;
|
||||
- the repository must have a Staging Area configured;
|
||||
- you must configure a Buildkite pipeline for that Staging Area; and
|
||||
- you must configure the webhook described below.
|
||||
|
||||
To build **commits** with Buildkite, they must:
|
||||
|
||||
- belong to a tracked repository;
|
||||
- you must configure a Buildkite pipeline for that repository; and
|
||||
- you must configure the webhook described below.
|
||||
|
||||
Webhook Configuration
|
||||
=====================
|
||||
|
||||
In {nav Settings} for your Organization in Buildkite, under
|
||||
{nav Notification Services}, add a new **Webook Notification**.
|
||||
|
||||
Use these settings:
|
||||
|
||||
- **Webhook URL**: %s
|
||||
- **Token**: The "Webhook Token" field below and the "Token" field in
|
||||
Buildkite should both be set to the same nonempty value (any random
|
||||
secret). You can use copy/paste the value Buildkite generates into
|
||||
this form.
|
||||
- **Events**: Only **build.finish** needs to be active.
|
||||
|
||||
Environment
|
||||
===========
|
||||
|
||||
These variables will be available in the build environment:
|
||||
|
||||
| Variable | Description |
|
||||
|----------|-------------|
|
||||
| `HARBORMASTER_BUILD_TARGET_PHID` | PHID of the Build Target.
|
||||
EOTEXT
|
||||
,
|
||||
$hook_uri);
|
||||
}
|
||||
|
||||
public function execute(
|
||||
HarbormasterBuild $build,
|
||||
HarbormasterBuildTarget $build_target) {
|
||||
$viewer = PhabricatorUser::getOmnipotentUser();
|
||||
|
||||
$buildable = $build->getBuildable();
|
||||
|
||||
$object = $buildable->getBuildableObject();
|
||||
if (!($object instanceof HarbormasterBuildkiteBuildableInterface)) {
|
||||
throw new Exception(
|
||||
pht('This object does not support builds with Buildkite.'));
|
||||
}
|
||||
|
||||
$organization = $this->getSetting('organization');
|
||||
$pipeline = $this->getSetting('pipeline');
|
||||
|
||||
$uri = urisprintf(
|
||||
'https://api.buildkite.com/v2/organizations/%s/pipelines/%s/builds',
|
||||
$organization,
|
||||
$pipeline);
|
||||
|
||||
$data_structure = array(
|
||||
'commit' => $object->getBuildkiteCommit(),
|
||||
'branch' => $object->getBuildkiteBranch(),
|
||||
'message' => pht(
|
||||
'Harbormaster Build %s ("%s") for %s',
|
||||
$build->getID(),
|
||||
$build->getName(),
|
||||
$buildable->getMonogram()),
|
||||
'env' => array(
|
||||
'HARBORMASTER_BUILD_TARGET_PHID' => $build_target->getPHID(),
|
||||
),
|
||||
'meta_data' => array(
|
||||
'buildTargetPHID' => $build_target->getPHID(),
|
||||
),
|
||||
);
|
||||
|
||||
$json_data = phutil_json_encode($data_structure);
|
||||
|
||||
$credential_phid = $this->getSetting('token');
|
||||
$api_token = id(new PassphraseCredentialQuery())
|
||||
->setViewer($viewer)
|
||||
->withPHIDs(array($credential_phid))
|
||||
->needSecrets(true)
|
||||
->executeOne();
|
||||
if (!$api_token) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Unable to load API token ("%s")!',
|
||||
$credential_phid));
|
||||
}
|
||||
|
||||
$token = $api_token->getSecret()->openEnvelope();
|
||||
|
||||
$future = id(new HTTPSFuture($uri, $json_data))
|
||||
->setMethod('POST')
|
||||
->addHeader('Content-Type', 'application/json')
|
||||
->addHeader('Accept', 'application/json')
|
||||
->addHeader('Authorization', "Bearer {$token}")
|
||||
->setTimeout(60);
|
||||
|
||||
$this->resolveFutures(
|
||||
$build,
|
||||
$build_target,
|
||||
array($future));
|
||||
|
||||
$this->logHTTPResponse($build, $build_target, $future, pht('Buildkite'));
|
||||
|
||||
list($status, $body) = $future->resolve();
|
||||
if ($status->isError()) {
|
||||
throw new HarbormasterBuildFailureException();
|
||||
}
|
||||
|
||||
$response = phutil_json_decode($body);
|
||||
|
||||
$uri_key = 'web_url';
|
||||
$build_uri = idx($response, $uri_key);
|
||||
if (!$build_uri) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Buildkite did not return a "%s"!',
|
||||
$uri_key));
|
||||
}
|
||||
|
||||
$target_phid = $build_target->getPHID();
|
||||
|
||||
$api_method = 'harbormaster.createartifact';
|
||||
$api_params = array(
|
||||
'buildTargetPHID' => $target_phid,
|
||||
'artifactType' => HarbormasterURIArtifact::ARTIFACTCONST,
|
||||
'artifactKey' => 'buildkite.uri',
|
||||
'artifactData' => array(
|
||||
'uri' => $build_uri,
|
||||
'name' => pht('View in Buildkite'),
|
||||
'ui.external' => true,
|
||||
),
|
||||
);
|
||||
|
||||
id(new ConduitCall($api_method, $api_params))
|
||||
->setUser($viewer)
|
||||
->execute();
|
||||
}
|
||||
|
||||
public function getFieldSpecifications() {
|
||||
return array(
|
||||
'token' => array(
|
||||
'name' => pht('API Token'),
|
||||
'type' => 'credential',
|
||||
'credential.type'
|
||||
=> PassphraseTokenCredentialType::CREDENTIAL_TYPE,
|
||||
'credential.provides'
|
||||
=> PassphraseTokenCredentialType::PROVIDES_TYPE,
|
||||
'required' => true,
|
||||
),
|
||||
'organization' => array(
|
||||
'name' => pht('Organization Name'),
|
||||
'type' => 'text',
|
||||
'required' => true,
|
||||
),
|
||||
'pipeline' => array(
|
||||
'name' => pht('Pipeline Name'),
|
||||
'type' => 'text',
|
||||
'required' => true,
|
||||
),
|
||||
'webhook.token' => array(
|
||||
'name' => pht('Webhook Token'),
|
||||
'type' => 'text',
|
||||
'required' => true,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
public function supportsWaitForMessage() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public function shouldWaitForMessage(HarbormasterBuildTarget $target) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -22,15 +22,17 @@ final class PhabricatorHomeApplication extends PhabricatorApplication {
|
|||
|
||||
public function getRoutes() {
|
||||
return array(
|
||||
'/' => 'PhabricatorHomeMainController',
|
||||
'/(?P<only>home)/' => 'PhabricatorHomeMainController',
|
||||
'/home/' => array(
|
||||
'menu/' => array(
|
||||
'' => 'PhabricatorHomeMenuController',
|
||||
'(?P<type>global|personal)/item/' => $this->getProfileMenuRouting(
|
||||
'/' => 'PhabricatorHomeMenuItemController',
|
||||
|
||||
// NOTE: If you visit "/" on mobile, you get just the menu. If you visit
|
||||
// "/home/" on mobile, you get the content. From the normal desktop
|
||||
// UI, there's no difference between these pages.
|
||||
|
||||
'/(?P<content>home)/' => array(
|
||||
'' => 'PhabricatorHomeMenuItemController',
|
||||
'menu/' => $this->getProfileMenuRouting(
|
||||
'PhabricatorHomeMenuItemController'),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,9 @@
|
|||
final class PhabricatorHomeConstants
|
||||
extends PhabricatorHomeController {
|
||||
|
||||
const ITEM_HOME = 'home.dashboard';
|
||||
const ITEM_LAUNCHER = 'home.launcher';
|
||||
const ITEM_MANAGE = 'home.manage.menu';
|
||||
const ITEM_APPS_LABEL = 'home.apps.label';
|
||||
|
||||
}
|
||||
|
|
|
@ -2,69 +2,42 @@
|
|||
|
||||
abstract class PhabricatorHomeController extends PhabricatorController {
|
||||
|
||||
public function buildNav() {
|
||||
$user = $this->getRequest()->getUser();
|
||||
private $home;
|
||||
private $profileMenu;
|
||||
|
||||
$nav = new AphrontSideNavFilterView();
|
||||
$nav->setBaseURI(new PhutilURI('/'));
|
||||
public function buildApplicationMenu() {
|
||||
$menu = $this->newApplicationMenu();
|
||||
|
||||
$profile_menu = $this->getProfileMenu();
|
||||
if ($profile_menu) {
|
||||
$menu->setProfileMenu($profile_menu);
|
||||
}
|
||||
|
||||
return $menu;
|
||||
}
|
||||
|
||||
protected function getProfileMenu() {
|
||||
if (!$this->profileMenu) {
|
||||
$viewer = $this->getViewer();
|
||||
$applications = id(new PhabricatorApplicationQuery())
|
||||
->setViewer($user)
|
||||
->setViewer($viewer)
|
||||
->withClasses(array('PhabricatorHomeApplication'))
|
||||
->withInstalled(true)
|
||||
->withUnlisted(false)
|
||||
->withLaunchable(true)
|
||||
->execute();
|
||||
|
||||
$pinned = $user->getUserSetting(
|
||||
PhabricatorPinnedApplicationsSetting::SETTINGKEY);
|
||||
|
||||
// Force "Applications" to appear at the bottom.
|
||||
$meta_app = 'PhabricatorApplicationsApplication';
|
||||
$pinned = array_fuse($pinned);
|
||||
unset($pinned[$meta_app]);
|
||||
$pinned[$meta_app] = $meta_app;
|
||||
$applications[$meta_app] = PhabricatorApplication::getByClass($meta_app);
|
||||
|
||||
$tiles = array();
|
||||
|
||||
$home_app = new PhabricatorHomeApplication();
|
||||
|
||||
$tiles[] = id(new PhabricatorApplicationLaunchView())
|
||||
->setApplication($home_app)
|
||||
->addClass('phabricator-application-launch-phone-only')
|
||||
->setUser($user);
|
||||
|
||||
foreach ($pinned as $pinned_application) {
|
||||
if (empty($applications[$pinned_application])) {
|
||||
continue;
|
||||
$home = head($applications);
|
||||
if (!$home) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$application = $applications[$pinned_application];
|
||||
$engine = id(new PhabricatorHomeProfileMenuEngine())
|
||||
->setViewer($viewer)
|
||||
->setProfileObject($home)
|
||||
->setCustomPHID($viewer->getPHID());
|
||||
|
||||
$tile = id(new PhabricatorApplicationLaunchView())
|
||||
->setApplication($application)
|
||||
->setUser($user);
|
||||
|
||||
$tiles[] = $tile;
|
||||
$this->profileMenu = $engine->buildNavigation();
|
||||
}
|
||||
|
||||
$nav->addCustomBlock(
|
||||
phutil_tag(
|
||||
'div',
|
||||
array(
|
||||
'class' => 'application-tile-group',
|
||||
),
|
||||
$tiles));
|
||||
|
||||
$nav->addFilter(
|
||||
'',
|
||||
pht('Customize Menu...'),
|
||||
'/settings/panel/home/');
|
||||
|
||||
$nav->addClass('phabricator-side-menu-home');
|
||||
$nav->selectFilter(null);
|
||||
|
||||
return $nav;
|
||||
return $this->profileMenu;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,57 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorHomeMenuController extends PhabricatorHomeController {
|
||||
|
||||
public function shouldAllowPublic() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$viewer = $request->getViewer();
|
||||
|
||||
$menu = id(new PHUIObjectItemListView())
|
||||
->setUser($viewer);
|
||||
|
||||
$menu->addItem(
|
||||
id(new PHUIObjectItemView())
|
||||
->setHeader(pht('Personal Menu Items'))
|
||||
->setHref($this->getApplicationURI('menu/personal/item/configure/'))
|
||||
->setImageURI($viewer->getProfileImageURI())
|
||||
->addAttribute(pht('Edit the menu for your personal account.')));
|
||||
|
||||
$icon = id(new PHUIIconView())
|
||||
->setIcon('fa-globe')
|
||||
->setBackground('bg-blue');
|
||||
|
||||
$menu->addItem(
|
||||
id(new PHUIObjectItemView())
|
||||
->setHeader(pht('Global Menu Items'))
|
||||
->setHref($this->getApplicationURI('menu/global/item/configure/'))
|
||||
->setImageIcon($icon)
|
||||
->addAttribute(pht('Edit the global default menu for all users.')));
|
||||
|
||||
$crumbs = $this->buildApplicationCrumbs();
|
||||
$crumbs->addTextCrumb(pht('Manage'));
|
||||
$crumbs->setBorder(true);
|
||||
|
||||
$box = id(new PHUIObjectBoxView())
|
||||
->setObjectList($menu);
|
||||
|
||||
$header = id(new PHUIHeaderView())
|
||||
->setHeader(pht('Manage Home Menu'))
|
||||
->setHeaderIcon('fa-home');
|
||||
|
||||
$view = id(new PHUITwoColumnView())
|
||||
->setHeader($header)
|
||||
->setFooter(array(
|
||||
$box,
|
||||
));
|
||||
|
||||
return $this->newPage()
|
||||
->setTitle(pht('Manage Home Menu'))
|
||||
->setCrumbs($crumbs)
|
||||
->appendChild($view);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -3,15 +3,21 @@
|
|||
final class PhabricatorHomeMenuItemController
|
||||
extends PhabricatorHomeController {
|
||||
|
||||
public function shouldAllowPublic() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function isGlobalDragAndDropUploadEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$viewer = $this->getViewer();
|
||||
$type = $request->getURIData('type');
|
||||
$custom_phid = null;
|
||||
$menu = PhabricatorProfileMenuEngine::MENU_GLOBAL;
|
||||
if ($type == 'personal') {
|
||||
$custom_phid = $viewer->getPHID();
|
||||
$menu = PhabricatorProfileMenuEngine::MENU_PERSONAL;
|
||||
}
|
||||
|
||||
// Test if we should show mobile users the menu or the page content:
|
||||
// if you visit "/", you just get the menu. If you visit "/home/", you
|
||||
// get the content.
|
||||
$is_content = $request->getURIData('content');
|
||||
|
||||
$application = 'PhabricatorHomeApplication';
|
||||
$home_app = id(new PhabricatorApplicationQuery())
|
||||
|
@ -22,10 +28,13 @@ final class PhabricatorHomeMenuItemController
|
|||
|
||||
$engine = id(new PhabricatorHomeProfileMenuEngine())
|
||||
->setProfileObject($home_app)
|
||||
->setCustomPHID($custom_phid)
|
||||
->setMenuType($menu)
|
||||
->setCustomPHID($viewer->getPHID())
|
||||
->setController($this)
|
||||
->setShowNavigation(false);
|
||||
->setShowContentCrumbs(false);
|
||||
|
||||
if (!$is_content) {
|
||||
$engine->addContentPageClass('phabricator-home');
|
||||
}
|
||||
|
||||
return $engine->buildResponse();
|
||||
}
|
||||
|
|
|
@ -8,14 +8,25 @@ final class PhabricatorHomeProfileMenuEngine
|
|||
}
|
||||
|
||||
public function getItemURI($path) {
|
||||
$object = $this->getProfileObject();
|
||||
$custom = $this->getCustomPHID();
|
||||
|
||||
if ($custom) {
|
||||
return "/home/menu/personal/item/{$path}";
|
||||
} else {
|
||||
return "/home/menu/global/item/{$path}";
|
||||
return "/home/menu/{$path}";
|
||||
}
|
||||
|
||||
protected function buildItemViewContent(
|
||||
PhabricatorProfileMenuItemConfiguration $item) {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
// Add content to the document so that you can drag-and-drop files onto
|
||||
// the home page or any home dashboard to upload them.
|
||||
|
||||
$upload = id(new PhabricatorGlobalUploadTargetView())
|
||||
->setUser($viewer);
|
||||
|
||||
$content = parent::buildItemViewContent($item);
|
||||
|
||||
return array(
|
||||
$content,
|
||||
$upload,
|
||||
);
|
||||
}
|
||||
|
||||
protected function getBuiltinProfileItems($object) {
|
||||
|
@ -30,13 +41,23 @@ final class PhabricatorHomeProfileMenuEngine
|
|||
->withLaunchable(true)
|
||||
->execute();
|
||||
|
||||
// Default Home Dashboard
|
||||
$items[] = $this->newItem()
|
||||
->setBuiltinKey(PhabricatorHomeConstants::ITEM_HOME)
|
||||
->setMenuItemKey(PhabricatorHomeProfileMenuItem::MENUITEMKEY);
|
||||
|
||||
$items[] = $this->newItem()
|
||||
->setBuiltinKey(PhabricatorHomeConstants::ITEM_APPS_LABEL)
|
||||
->setMenuItemKey(PhabricatorLabelProfileMenuItem::MENUITEMKEY)
|
||||
->setMenuItemProperties(array('name' => pht('Applications')));
|
||||
|
||||
foreach ($applications as $application) {
|
||||
if (!$application->isPinnedByDefault($viewer)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$properties = array(
|
||||
'name' => $application->getName(),
|
||||
'name' => '',
|
||||
'application' => $application->getPHID(),
|
||||
);
|
||||
|
||||
|
@ -46,11 +67,12 @@ final class PhabricatorHomeProfileMenuEngine
|
|||
->setMenuItemProperties($properties);
|
||||
}
|
||||
|
||||
// Single Manage Item, switches URI based on admin/user
|
||||
// Hotlink to More Applications Launcher...
|
||||
$items[] = $this->newItem()
|
||||
->setBuiltinKey(PhabricatorHomeConstants::ITEM_MANAGE)
|
||||
->setMenuItemKey(
|
||||
PhabricatorHomeManageProfileMenuItem::MENUITEMKEY);
|
||||
->setBuiltinKey(PhabricatorHomeConstants::ITEM_LAUNCHER)
|
||||
->setMenuItemKey(PhabricatorHomeLauncherProfileMenuItem::MENUITEMKEY);
|
||||
|
||||
$items[] = $this->newManageItem();
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorHomeLauncherProfileMenuItem
|
||||
extends PhabricatorProfileMenuItem {
|
||||
|
||||
const MENUITEMKEY = 'home.launcher.menu';
|
||||
|
||||
public function getMenuItemTypeName() {
|
||||
return pht('More Applications');
|
||||
}
|
||||
|
||||
private function getDefaultName() {
|
||||
return pht('More Applications');
|
||||
}
|
||||
|
||||
public function canHideMenuItem(
|
||||
PhabricatorProfileMenuItemConfiguration $config) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public function canMakeDefault(
|
||||
PhabricatorProfileMenuItemConfiguration $config) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getDisplayName(
|
||||
PhabricatorProfileMenuItemConfiguration $config) {
|
||||
$name = $config->getMenuItemProperty('name');
|
||||
|
||||
if (strlen($name)) {
|
||||
return $name;
|
||||
}
|
||||
|
||||
return $this->getDefaultName();
|
||||
}
|
||||
|
||||
public function buildEditEngineFields(
|
||||
PhabricatorProfileMenuItemConfiguration $config) {
|
||||
return array(
|
||||
id(new PhabricatorTextEditField())
|
||||
->setKey('name')
|
||||
->setLabel(pht('Name'))
|
||||
->setPlaceholder($this->getDefaultName())
|
||||
->setValue($config->getMenuItemProperty('name')),
|
||||
);
|
||||
}
|
||||
|
||||
protected function newNavigationMenuItems(
|
||||
PhabricatorProfileMenuItemConfiguration $config) {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$name = $this->getDisplayName($config);
|
||||
$icon = 'fa-globe';
|
||||
$href = '/applications/';
|
||||
|
||||
$item = $this->newItem()
|
||||
->setHref($href)
|
||||
->setName($name)
|
||||
->setIcon($icon);
|
||||
|
||||
return array(
|
||||
$item,
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorHomeProfileMenuItem
|
||||
extends PhabricatorProfileMenuItem {
|
||||
|
||||
const MENUITEMKEY = 'home.dashboard';
|
||||
|
||||
public function getMenuItemTypeName() {
|
||||
return pht('Built-in Homepage');
|
||||
}
|
||||
|
||||
private function getDefaultName() {
|
||||
return pht('Home');
|
||||
}
|
||||
|
||||
public function canMakeDefault(
|
||||
PhabricatorProfileMenuItemConfiguration $config) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getDisplayName(
|
||||
PhabricatorProfileMenuItemConfiguration $config) {
|
||||
$name = $config->getMenuItemProperty('name');
|
||||
|
||||
if (strlen($name)) {
|
||||
return $name;
|
||||
}
|
||||
|
||||
return $this->getDefaultName();
|
||||
}
|
||||
|
||||
public function newPageContent(
|
||||
PhabricatorProfileMenuItemConfiguration $config) {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
return id(new PHUIHomeView())
|
||||
->setViewer($viewer);
|
||||
}
|
||||
|
||||
public function buildEditEngineFields(
|
||||
PhabricatorProfileMenuItemConfiguration $config) {
|
||||
return array(
|
||||
id(new PhabricatorTextEditField())
|
||||
->setKey('name')
|
||||
->setLabel(pht('Name'))
|
||||
->setPlaceholder($this->getDefaultName())
|
||||
->setValue($config->getMenuItemProperty('name')),
|
||||
);
|
||||
}
|
||||
|
||||
protected function newNavigationMenuItems(
|
||||
PhabricatorProfileMenuItemConfiguration $config) {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$name = $this->getDisplayName($config);
|
||||
$icon = 'fa-home';
|
||||
$href = $this->getItemViewURI($config);
|
||||
|
||||
$item = $this->newItem()
|
||||
->setHref($href)
|
||||
->setName($name)
|
||||
->setIcon($icon);
|
||||
|
||||
return array(
|
||||
$item,
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,57 +1,17 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorHomeMainController extends PhabricatorHomeController {
|
||||
final class PHUIHomeView
|
||||
extends AphrontTagView {
|
||||
|
||||
public function shouldAllowPublic() {
|
||||
return true;
|
||||
protected function getTagName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public function isGlobalDragAndDropUploadEnabled() {
|
||||
return true;
|
||||
protected function getTagAttributes() {
|
||||
return array();
|
||||
}
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$viewer = $request->getViewer();
|
||||
|
||||
$dashboard = PhabricatorDashboardInstall::getDashboard(
|
||||
$viewer,
|
||||
$viewer->getPHID(),
|
||||
get_class($this->getCurrentApplication()));
|
||||
|
||||
if (!$dashboard) {
|
||||
$dashboard = PhabricatorDashboardInstall::getDashboard(
|
||||
$viewer,
|
||||
PhabricatorHomeApplication::DASHBOARD_DEFAULT,
|
||||
get_class($this->getCurrentApplication()));
|
||||
}
|
||||
|
||||
if ($dashboard) {
|
||||
$content = id(new PhabricatorDashboardRenderingEngine())
|
||||
->setViewer($viewer)
|
||||
->setDashboard($dashboard)
|
||||
->renderDashboard();
|
||||
} else {
|
||||
$content = $this->buildMainResponse();
|
||||
}
|
||||
|
||||
if (!$request->getURIData('only')) {
|
||||
$nav = $this->buildNav();
|
||||
$nav->appendChild(
|
||||
array(
|
||||
$content,
|
||||
id(new PhabricatorGlobalUploadTargetView())->setUser($viewer),
|
||||
));
|
||||
$content = $nav;
|
||||
}
|
||||
|
||||
return $this->newPage()
|
||||
->setTitle('Phabricator')
|
||||
->addClass('phabricator-home')
|
||||
->appendChild($content);
|
||||
|
||||
}
|
||||
|
||||
private function buildMainResponse() {
|
||||
protected function getTagContent() {
|
||||
require_celerity_resource('phabricator-dashboard-css');
|
||||
$viewer = $this->getViewer();
|
||||
|
|
@ -185,6 +185,7 @@ final class PhabricatorMacroEditController extends PhabricatorMacroController {
|
|||
if (!$macro->getID()) {
|
||||
if ($current_file) {
|
||||
$current_file_view = id(new PhabricatorFileLinkView())
|
||||
->setViewer($viewer)
|
||||
->setFilePHID($current_file->getPHID())
|
||||
->setFileName($current_file->getName())
|
||||
->setFileViewable(true)
|
||||
|
|
|
@ -1,69 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorApplicationLaunchView extends AphrontTagView {
|
||||
|
||||
private $application;
|
||||
|
||||
public function setApplication(PhabricatorApplication $application) {
|
||||
$this->application = $application;
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function getTagName() {
|
||||
return $this->application ? 'a' : 'div';
|
||||
}
|
||||
|
||||
protected function getTagAttributes() {
|
||||
$application = $this->application;
|
||||
return array(
|
||||
'class' => array('phabricator-application-launch-container'),
|
||||
'href' => $application ? $application->getBaseURI() : null,
|
||||
);
|
||||
}
|
||||
|
||||
protected function getTagContent() {
|
||||
$application = $this->application;
|
||||
|
||||
require_celerity_resource('phabricator-application-launch-view-css');
|
||||
|
||||
$content = array();
|
||||
$icon = null;
|
||||
if ($application) {
|
||||
$content[] = phutil_tag(
|
||||
'span',
|
||||
array(
|
||||
'class' => 'phabricator-application-launch-name',
|
||||
),
|
||||
$application->getName());
|
||||
|
||||
$content[] = phutil_tag(
|
||||
'span',
|
||||
array(
|
||||
'class' => 'phabricator-application-launch-description',
|
||||
),
|
||||
$application->getShortDescription());
|
||||
|
||||
$classes = array();
|
||||
$classes[] = 'phabricator-application-launch-icon';
|
||||
|
||||
$styles = array();
|
||||
$classes[] = $application->getIcon();
|
||||
$classes[] = 'phui-icon-view';
|
||||
$classes[] = 'phui-font-fa';
|
||||
|
||||
$icon = phutil_tag(
|
||||
'span',
|
||||
array(
|
||||
'class' => implode(' ', $classes),
|
||||
'style' => nonempty(implode('; ', $styles), null),
|
||||
),
|
||||
'');
|
||||
}
|
||||
|
||||
return array(
|
||||
$icon,
|
||||
$content,
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -68,14 +68,14 @@ final class PhabricatorOwnersDetailController
|
|||
$commit_uri = id(new PhutilURI('/diffusion/commit/'))
|
||||
->setQueryParams(
|
||||
array(
|
||||
'auditorPHIDs' => $package->getPHID(),
|
||||
'package' => $package->getPHID(),
|
||||
));
|
||||
|
||||
$status_concern = PhabricatorAuditCommitStatusConstants::CONCERN_RAISED;
|
||||
|
||||
$attention_commits = id(new DiffusionCommitQuery())
|
||||
->setViewer($request->getUser())
|
||||
->withAuditorPHIDs(array($package->getPHID()))
|
||||
->withPackagePHIDs(array($package->getPHID()))
|
||||
->withStatuses(
|
||||
array(
|
||||
$status_concern,
|
||||
|
@ -102,7 +102,7 @@ final class PhabricatorOwnersDetailController
|
|||
|
||||
$all_commits = id(new DiffusionCommitQuery())
|
||||
->setViewer($request->getUser())
|
||||
->withAuditorPHIDs(array($package->getPHID()))
|
||||
->withPackagePHIDs(array($package->getPHID()))
|
||||
->needCommitData(true)
|
||||
->needAuditRequests(true)
|
||||
->setLimit(25)
|
||||
|
|
|
@ -60,4 +60,64 @@ abstract class PhabricatorPeopleProfileController
|
|||
return $crumbs;
|
||||
}
|
||||
|
||||
public function buildProfileHeader() {
|
||||
$user = $this->user;
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$profile = $user->loadUserProfile();
|
||||
$picture = $user->getProfileImageURI();
|
||||
|
||||
$profile_icon = PhabricatorPeopleIconSet::getIconIcon($profile->getIcon());
|
||||
$profile_title = $profile->getDisplayTitle();
|
||||
|
||||
$roles = array();
|
||||
if ($user->getIsAdmin()) {
|
||||
$roles[] = pht('Administrator');
|
||||
}
|
||||
if ($user->getIsDisabled()) {
|
||||
$roles[] = pht('Disabled');
|
||||
}
|
||||
if (!$user->getIsApproved()) {
|
||||
$roles[] = pht('Not Approved');
|
||||
}
|
||||
if ($user->getIsSystemAgent()) {
|
||||
$roles[] = pht('Bot');
|
||||
}
|
||||
if ($user->getIsMailingList()) {
|
||||
$roles[] = pht('Mailing List');
|
||||
}
|
||||
|
||||
$tag = null;
|
||||
if ($roles) {
|
||||
$tag = id(new PHUITagView())
|
||||
->setName(implode(', ', $roles))
|
||||
->addClass('project-view-header-tag')
|
||||
->setType(PHUITagView::TYPE_SHADE);
|
||||
}
|
||||
|
||||
$header = id(new PHUIHeaderView())
|
||||
->setHeader(array($user->getFullName(), $tag))
|
||||
->setImage($picture)
|
||||
->setProfileHeader(true)
|
||||
->addClass('people-profile-header');
|
||||
|
||||
if ($user->getIsDisabled()) {
|
||||
$header->setStatus('fa-ban', 'red', pht('Disabled'));
|
||||
} else {
|
||||
$header->setStatus($profile_icon, 'bluegrey', $profile_title);
|
||||
}
|
||||
|
||||
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
||||
$viewer,
|
||||
$user,
|
||||
PhabricatorPolicyCapability::CAN_EDIT);
|
||||
|
||||
if ($can_edit) {
|
||||
$id = $user->getID();
|
||||
$header->setImageEditURL($this->getApplicationURI("picture/{$id}/"));
|
||||
}
|
||||
|
||||
return $header;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -23,20 +23,7 @@ final class PhabricatorPeopleProfileManageController
|
|||
}
|
||||
|
||||
$this->setUser($user);
|
||||
|
||||
$profile = $user->loadUserProfile();
|
||||
$picture = $user->getProfileImageURI();
|
||||
|
||||
$profile_icon = PhabricatorPeopleIconSet::getIconIcon($profile->getIcon());
|
||||
$profile_icon = id(new PHUIIconView())
|
||||
->setIcon($profile_icon);
|
||||
$profile_title = $profile->getDisplayTitle();
|
||||
|
||||
$header = id(new PHUIHeaderView())
|
||||
->setHeader($user->getFullName())
|
||||
->setSubheader(array($profile_icon, $profile_title))
|
||||
->setImage($picture)
|
||||
->setProfileHeader(true);
|
||||
$header = $this->buildProfileHeader();
|
||||
|
||||
$curtain = $this->buildCurtain($user);
|
||||
$properties = $this->buildPropertyView($user);
|
||||
|
@ -51,8 +38,10 @@ final class PhabricatorPeopleProfileManageController
|
|||
|
||||
$manage = id(new PHUITwoColumnView())
|
||||
->setHeader($header)
|
||||
->addClass('project-view-home')
|
||||
->setCurtain($curtain)
|
||||
->addPropertySection(pht('Details'), $properties);
|
||||
require_celerity_resource('project-view-css');
|
||||
|
||||
return $this->newPage()
|
||||
->setTitle(
|
||||
|
|
|
@ -23,30 +23,7 @@ final class PhabricatorPeopleProfileViewController
|
|||
}
|
||||
|
||||
$this->setUser($user);
|
||||
|
||||
$profile = $user->loadUserProfile();
|
||||
$picture = $user->getProfileImageURI();
|
||||
|
||||
$profile_icon = PhabricatorPeopleIconSet::getIconIcon($profile->getIcon());
|
||||
$profile_icon = id(new PHUIIconView())
|
||||
->setIcon($profile_icon);
|
||||
$profile_title = $profile->getDisplayTitle();
|
||||
|
||||
$header = id(new PHUIHeaderView())
|
||||
->setHeader($user->getFullName())
|
||||
->setSubheader(array($profile_icon, $profile_title))
|
||||
->setImage($picture)
|
||||
->setProfileHeader(true);
|
||||
|
||||
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
||||
$viewer,
|
||||
$user,
|
||||
PhabricatorPolicyCapability::CAN_EDIT);
|
||||
|
||||
if ($can_edit) {
|
||||
$id = $user->getID();
|
||||
$header->setImageEditURL($this->getApplicationURI("picture/{$id}/"));
|
||||
}
|
||||
$header = $this->buildProfileHeader();
|
||||
|
||||
$properties = $this->buildPropertyView($user);
|
||||
$name = $user->getUsername();
|
||||
|
@ -158,12 +135,9 @@ final class PhabricatorPeopleProfileViewController
|
|||
}
|
||||
|
||||
} else {
|
||||
$error = id(new PHUIBoxView())
|
||||
->addClass('mlb')
|
||||
->appendChild(pht('User does not belong to any projects.'));
|
||||
$list = id(new PHUIInfoView())
|
||||
->setSeverity(PHUIInfoView::SEVERITY_NODATA)
|
||||
->appendChild($error);
|
||||
->appendChild(pht('User does not belong to any projects.'));
|
||||
}
|
||||
|
||||
$box = id(new PHUIObjectBoxView())
|
||||
|
@ -302,12 +276,9 @@ final class PhabricatorPeopleProfileViewController
|
|||
}
|
||||
}
|
||||
} else {
|
||||
$error = id(new PHUIBoxView())
|
||||
->addClass('mlb')
|
||||
->appendChild(pht('User does not have any badges.'));
|
||||
$flex = id(new PHUIInfoView())
|
||||
->setSeverity(PHUIInfoView::SEVERITY_NODATA)
|
||||
->appendChild($error);
|
||||
->appendChild(pht('User does not have any badges.'));
|
||||
}
|
||||
|
||||
// Best option?
|
||||
|
|
|
@ -5,6 +5,7 @@ final class PhabricatorPeopleProfileMenuEngine
|
|||
|
||||
const ITEM_PROFILE = 'people.profile';
|
||||
const ITEM_MANAGE = 'people.manage';
|
||||
const ITEM_PICTURE = 'people.picture';
|
||||
|
||||
protected function isMenuEngineConfigurable() {
|
||||
return false;
|
||||
|
@ -22,6 +23,10 @@ final class PhabricatorPeopleProfileMenuEngine
|
|||
|
||||
$items = array();
|
||||
|
||||
$items[] = $this->newItem()
|
||||
->setBuiltinKey(self::ITEM_PICTURE)
|
||||
->setMenuItemKey(PhabricatorPeoplePictureProfileMenuItem::MENUITEMKEY);
|
||||
|
||||
$items[] = $this->newItem()
|
||||
->setBuiltinKey(self::ITEM_PROFILE)
|
||||
->setMenuItemKey(PhabricatorPeopleDetailsProfileMenuItem::MENUITEMKEY);
|
||||
|
|
|
@ -39,17 +39,14 @@ final class PhabricatorPeopleDetailsProfileMenuItem
|
|||
PhabricatorProfileMenuItemConfiguration $config) {
|
||||
|
||||
$user = $config->getProfileObject();
|
||||
|
||||
$picture = $user->getProfileImageURI();
|
||||
$name = $user->getUsername();
|
||||
$href = urisprintf(
|
||||
'/p/%s/',
|
||||
$user->getUsername());
|
||||
|
||||
$item = $this->newItem()
|
||||
->setHref($href)
|
||||
->setName($name)
|
||||
->setProfileImage($picture);
|
||||
->setName(pht('Profile'))
|
||||
->setIcon('fa-user');
|
||||
|
||||
return array(
|
||||
$item,
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorPeoplePictureProfileMenuItem
|
||||
extends PhabricatorProfileMenuItem {
|
||||
|
||||
const MENUITEMKEY = 'people.picture';
|
||||
|
||||
public function getMenuItemTypeName() {
|
||||
return pht('User Picture');
|
||||
}
|
||||
|
||||
private function getDefaultName() {
|
||||
return pht('User Picture');
|
||||
}
|
||||
|
||||
public function canHideMenuItem(
|
||||
PhabricatorProfileMenuItemConfiguration $config) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getDisplayName(
|
||||
PhabricatorProfileMenuItemConfiguration $config) {
|
||||
return $this->getDefaultName();
|
||||
}
|
||||
|
||||
public function buildEditEngineFields(
|
||||
PhabricatorProfileMenuItemConfiguration $config) {
|
||||
return array();
|
||||
}
|
||||
|
||||
protected function newNavigationMenuItems(
|
||||
PhabricatorProfileMenuItemConfiguration $config) {
|
||||
|
||||
$user = $config->getProfileObject();
|
||||
require_celerity_resource('people-picture-menu-item-css');
|
||||
|
||||
$picture = $user->getProfileImageURI();
|
||||
$name = $user->getUsername();
|
||||
$href = urisprintf(
|
||||
'/p/%s/',
|
||||
$user->getUsername());
|
||||
|
||||
$photo = phutil_tag(
|
||||
'img',
|
||||
array(
|
||||
'src' => $picture,
|
||||
'class' => 'people-menu-image',
|
||||
));
|
||||
|
||||
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
||||
$this->getViewer(),
|
||||
$user,
|
||||
PhabricatorPolicyCapability::CAN_EDIT);
|
||||
|
||||
if ($can_edit) {
|
||||
$id = $user->getID();
|
||||
$href = "/people/picture/{$id}/";
|
||||
}
|
||||
|
||||
$view = phutil_tag_div('people-menu-image-container', $photo);
|
||||
$view = phutil_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => $href,
|
||||
),
|
||||
$view);
|
||||
|
||||
$item = $this->newItem()
|
||||
->appendChild($view);
|
||||
|
||||
return array(
|
||||
$item,
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -180,8 +180,6 @@ final class PholioMockImagesView extends AphrontView {
|
|||
'pholio-mock-view',
|
||||
$this->getBehaviorConfig());
|
||||
|
||||
$mockview = '';
|
||||
|
||||
$mock_wrapper = javelin_tag(
|
||||
'div',
|
||||
array(
|
||||
|
@ -220,7 +218,7 @@ final class PholioMockImagesView extends AphrontView {
|
|||
),
|
||||
'');
|
||||
|
||||
$mockview[] = phutil_tag(
|
||||
return phutil_tag(
|
||||
'div',
|
||||
array(
|
||||
'class' => 'pholio-mock-image-container',
|
||||
|
@ -228,7 +226,6 @@ final class PholioMockImagesView extends AphrontView {
|
|||
),
|
||||
array($mock_wrapper, $inline_comments_holder));
|
||||
|
||||
return $mockview;
|
||||
}
|
||||
|
||||
private function getImagePageURI(PholioImage $image, PholioMock $mock) {
|
||||
|
|
|
@ -7,7 +7,7 @@ final class PhabricatorProjectApplication extends PhabricatorApplication {
|
|||
}
|
||||
|
||||
public function getShortDescription() {
|
||||
return pht('Get Organized');
|
||||
return pht('Projects, Tags, and Teams');
|
||||
}
|
||||
|
||||
public function isPinnedByDefault(PhabricatorUser $viewer) {
|
||||
|
|
|
@ -7,6 +7,10 @@ final class PhabricatorProjectProfileMenuEngine
|
|||
return true;
|
||||
}
|
||||
|
||||
protected function isMenuEnginePersonalizable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getItemURI($path) {
|
||||
$project = $this->getProfileObject();
|
||||
$id = $project->getID();
|
||||
|
|
|
@ -68,17 +68,16 @@ final class PhabricatorProjectPointsProfileMenuItem
|
|||
->setLimit($limit + 1)
|
||||
->execute();
|
||||
|
||||
$error = array();
|
||||
if (count($tasks) > $limit) {
|
||||
return $this->renderError(
|
||||
$error[] =
|
||||
pht(
|
||||
'Too many tasks to compute statistics for (more than %s).',
|
||||
new PhutilNumber($limit)));
|
||||
'Too many tasks (%s).',
|
||||
new PhutilNumber($limit));
|
||||
}
|
||||
|
||||
if (!$tasks) {
|
||||
return $this->renderError(
|
||||
pht(
|
||||
'This milestone has no tasks yet.'));
|
||||
$error[] = pht('This milestone has no tasks.');
|
||||
}
|
||||
|
||||
$statuses = array();
|
||||
|
@ -111,14 +110,11 @@ final class PhabricatorProjectPointsProfileMenuItem
|
|||
}
|
||||
|
||||
if ($no_points == count($tasks)) {
|
||||
return $this->renderError(
|
||||
pht('No tasks have assigned point values.'));
|
||||
$error[] = pht('No tasks have points assigned.');
|
||||
}
|
||||
|
||||
|
||||
if (!$points_total) {
|
||||
return $this->renderError(
|
||||
pht('All tasks with assigned point values are worth zero points.'));
|
||||
$error[] = pht('No tasks have positive points.');
|
||||
}
|
||||
|
||||
$label = pht(
|
||||
|
@ -158,6 +154,10 @@ final class PhabricatorProjectPointsProfileMenuItem
|
|||
->setTooltip($tooltip);
|
||||
}
|
||||
|
||||
if ($error) {
|
||||
$bar->setLabel(head($error));
|
||||
}
|
||||
|
||||
$bar = phutil_tag(
|
||||
'div',
|
||||
array(
|
||||
|
@ -173,20 +173,4 @@ final class PhabricatorProjectPointsProfileMenuItem
|
|||
);
|
||||
}
|
||||
|
||||
private function renderError($message) {
|
||||
$message = phutil_tag(
|
||||
'div',
|
||||
array(
|
||||
'class' => 'phui-profile-menu-error',
|
||||
),
|
||||
$message);
|
||||
|
||||
$item = $this->newItem()
|
||||
->appendChild($message);
|
||||
|
||||
return array(
|
||||
$item,
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ final class PhabricatorRepositoryCommit
|
|||
PhabricatorMentionableInterface,
|
||||
HarbormasterBuildableInterface,
|
||||
HarbormasterCircleCIBuildableInterface,
|
||||
HarbormasterBuildkiteBuildableInterface,
|
||||
PhabricatorCustomFieldInterface,
|
||||
PhabricatorApplicationTransactionInterface,
|
||||
PhabricatorFulltextInterface,
|
||||
|
@ -262,6 +263,29 @@ final class PhabricatorRepositoryCommit
|
|||
return isset($map[$audit->getAuditorPHID()]);
|
||||
}
|
||||
|
||||
public function writeOwnersEdges(array $package_phids) {
|
||||
$src_phid = $this->getPHID();
|
||||
$edge_type = DiffusionCommitHasPackageEdgeType::EDGECONST;
|
||||
|
||||
$editor = new PhabricatorEdgeEditor();
|
||||
|
||||
$dst_phids = PhabricatorEdgeQuery::loadDestinationPHIDs(
|
||||
$src_phid,
|
||||
$edge_type);
|
||||
|
||||
foreach ($dst_phids as $dst_phid) {
|
||||
$editor->removeEdge($src_phid, $edge_type, $dst_phid);
|
||||
}
|
||||
|
||||
foreach ($package_phids as $package_phid) {
|
||||
$editor->addEdge($src_phid, $edge_type, $package_phid);
|
||||
}
|
||||
|
||||
$editor->save();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getAuditorPHIDsForEdit() {
|
||||
$audits = $this->getAudits();
|
||||
return mpull($audits, 'getAuditorPHID');
|
||||
|
@ -567,6 +591,44 @@ final class PhabricatorRepositoryCommit
|
|||
}
|
||||
|
||||
|
||||
/* -( HarbormasterBuildkiteBuildableInterface )---------------------------- */
|
||||
|
||||
|
||||
public function getBuildkiteBranch() {
|
||||
$viewer = PhabricatorUser::getOmnipotentUser();
|
||||
$repository = $this->getRepository();
|
||||
|
||||
$branches = DiffusionQuery::callConduitWithDiffusionRequest(
|
||||
$viewer,
|
||||
DiffusionRequest::newFromDictionary(
|
||||
array(
|
||||
'repository' => $repository,
|
||||
'user' => $viewer,
|
||||
)),
|
||||
'diffusion.branchquery',
|
||||
array(
|
||||
'contains' => $this->getCommitIdentifier(),
|
||||
'repository' => $repository->getPHID(),
|
||||
));
|
||||
|
||||
if (!$branches) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Commit "%s" is not an ancestor of any branch head, so it can not '.
|
||||
'be built with Buildkite.',
|
||||
$this->getCommitIdentifier()));
|
||||
}
|
||||
|
||||
$branch = head($branches);
|
||||
|
||||
return 'refs/heads/'.$branch['shortName'];
|
||||
}
|
||||
|
||||
public function getBuildkiteCommit() {
|
||||
return $this->getCommitIdentifier();
|
||||
}
|
||||
|
||||
|
||||
/* -( PhabricatorCustomFieldInterface )------------------------------------ */
|
||||
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ final class PhabricatorRepositoryCommitOwnersWorker
|
|||
private function triggerOwnerAudits(
|
||||
PhabricatorRepository $repository,
|
||||
PhabricatorRepositoryCommit $commit) {
|
||||
$viewer = PhabricatorUser::getOmnipotentUser();
|
||||
|
||||
if (!$repository->shouldPublish()) {
|
||||
return;
|
||||
|
@ -42,20 +43,29 @@ final class PhabricatorRepositoryCommitOwnersWorker
|
|||
$repository,
|
||||
$affected_paths);
|
||||
|
||||
$commit->writeOwnersEdges(mpull($affected_packages, 'getPHID'));
|
||||
|
||||
if (!$affected_packages) {
|
||||
return;
|
||||
}
|
||||
|
||||
$data = id(new PhabricatorRepositoryCommitData())->loadOneWhere(
|
||||
'commitID = %d',
|
||||
$commit->getID());
|
||||
$commit->attachCommitData($data);
|
||||
$commit = id(new DiffusionCommitQuery())
|
||||
->setViewer($viewer)
|
||||
->withPHIDs(array($commit->getPHID()))
|
||||
->needCommitData(true)
|
||||
->needAuditRequests(true)
|
||||
->executeOne();
|
||||
if (!$commit) {
|
||||
return;
|
||||
}
|
||||
|
||||
$data = $commit->getCommitData();
|
||||
|
||||
$author_phid = $data->getCommitDetail('authorPHID');
|
||||
$revision_id = $data->getCommitDetail('differential.revisionID');
|
||||
if ($revision_id) {
|
||||
$revision = id(new DifferentialRevisionQuery())
|
||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||
->setViewer($viewer)
|
||||
->withIDs(array($revision_id))
|
||||
->needReviewerStatus(true)
|
||||
->executeOne();
|
||||
|
@ -63,13 +73,10 @@ final class PhabricatorRepositoryCommitOwnersWorker
|
|||
$revision = null;
|
||||
}
|
||||
|
||||
$requests = id(new PhabricatorRepositoryAuditRequest())
|
||||
->loadAllWhere(
|
||||
'commitPHID = %s',
|
||||
$commit->getPHID());
|
||||
$requests = $commit->getAudits();
|
||||
$requests = mpull($requests, null, 'getAuditorPHID');
|
||||
|
||||
|
||||
$auditor_phids = array();
|
||||
foreach ($affected_packages as $package) {
|
||||
$request = idx($requests, $package->getPHID());
|
||||
if ($request) {
|
||||
|
@ -77,61 +84,78 @@ final class PhabricatorRepositoryCommitOwnersWorker
|
|||
continue;
|
||||
}
|
||||
|
||||
if ($package->getAuditingEnabled()) {
|
||||
$reasons = $this->checkAuditReasons(
|
||||
$should_audit = $this->shouldTriggerAudit(
|
||||
$commit,
|
||||
$package,
|
||||
$author_phid,
|
||||
$revision);
|
||||
|
||||
if ($reasons) {
|
||||
$audit_status = PhabricatorAuditStatusConstants::AUDIT_REQUIRED;
|
||||
} else {
|
||||
$audit_status = PhabricatorAuditStatusConstants::AUDIT_NOT_REQUIRED;
|
||||
}
|
||||
} else {
|
||||
$reasons = array();
|
||||
$audit_status = PhabricatorAuditStatusConstants::NONE;
|
||||
if (!$should_audit) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$relationship = new PhabricatorRepositoryAuditRequest();
|
||||
$relationship->setAuditorPHID($package->getPHID());
|
||||
$relationship->setCommitPHID($commit->getPHID());
|
||||
$relationship->setAuditReasons($reasons);
|
||||
$relationship->setAuditStatus($audit_status);
|
||||
|
||||
$relationship->save();
|
||||
|
||||
$requests[$package->getPHID()] = $relationship;
|
||||
$auditor_phids[] = $package->getPHID();
|
||||
}
|
||||
|
||||
$commit->updateAuditStatus($requests);
|
||||
$commit->save();
|
||||
// If none of the packages are triggering audits, we're all done.
|
||||
if (!$auditor_phids) {
|
||||
return;
|
||||
}
|
||||
|
||||
private function checkAuditReasons(
|
||||
$audit_type = DiffusionCommitAuditorsTransaction::TRANSACTIONTYPE;
|
||||
|
||||
$owners_phid = id(new PhabricatorOwnersApplication())
|
||||
->getPHID();
|
||||
|
||||
$content_source = $this->newContentSource();
|
||||
|
||||
$xactions = array();
|
||||
$xactions[] = $commit->getApplicationTransactionTemplate()
|
||||
->setTransactionType($audit_type)
|
||||
->setNewValue(
|
||||
array(
|
||||
'+' => array_fuse($auditor_phids),
|
||||
));
|
||||
|
||||
$editor = $commit->getApplicationTransactionEditor()
|
||||
->setActor($viewer)
|
||||
->setActingAsPHID($owners_phid)
|
||||
->setContinueOnNoEffect(true)
|
||||
->setContinueOnMissingFields(true)
|
||||
->setContentSource($content_source);
|
||||
|
||||
$editor->applyTransactions($commit, $xactions);
|
||||
}
|
||||
|
||||
private function shouldTriggerAudit(
|
||||
PhabricatorRepositoryCommit $commit,
|
||||
PhabricatorOwnersPackage $package,
|
||||
$author_phid,
|
||||
$revision) {
|
||||
|
||||
// Don't trigger an audit if auditing isn't enabled for the package.
|
||||
if (!$package->getAuditingEnabled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Trigger an audit if we don't recognize the commit's author.
|
||||
if (!$author_phid) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$owner_phids = PhabricatorOwnersOwner::loadAffiliatedUserPHIDs(
|
||||
array(
|
||||
$package->getID(),
|
||||
));
|
||||
$owner_phids = array_fuse($owner_phids);
|
||||
|
||||
$reasons = array();
|
||||
|
||||
if (!$author_phid) {
|
||||
$reasons[] = pht('Commit Author Not Recognized');
|
||||
} else if (isset($owner_phids[$author_phid])) {
|
||||
return $reasons;
|
||||
// Don't trigger an audit if the author is a package owner.
|
||||
if (isset($owner_phids[$author_phid])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Trigger an audit of there is no corresponding revision.
|
||||
if (!$revision) {
|
||||
$reasons[] = pht('No Revision Specified');
|
||||
return $reasons;
|
||||
return true;
|
||||
}
|
||||
|
||||
$accepted_statuses = array(
|
||||
|
@ -157,11 +181,13 @@ final class PhabricatorRepositoryCommitOwnersWorker
|
|||
}
|
||||
}
|
||||
|
||||
if (!$found_accept) {
|
||||
$reasons[] = pht('Owners Not Involved');
|
||||
// Don't trigger an audit if a package owner already reviewed the
|
||||
// revision.
|
||||
if ($found_accept) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $reasons;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -169,12 +169,15 @@ final class PhabricatorApplicationSearchController
|
|||
}
|
||||
|
||||
$submit = id(new AphrontFormSubmitControl())
|
||||
->setValue(pht('Execute Query'));
|
||||
->setValue(pht('Search'));
|
||||
|
||||
if ($run_query && !$named_query && $user->isLoggedIn()) {
|
||||
$submit->addCancelButton(
|
||||
'/search/edit/'.$saved_query->getQueryKey().'/',
|
||||
pht('Save Custom Query...'));
|
||||
$save_button = id(new PHUIButtonView())
|
||||
->setTag('a')
|
||||
->setHref('/search/edit/'.$saved_query->getQueryKey().'/')
|
||||
->setText(pht('Save Query'))
|
||||
->setIcon('fa-floppy-o');
|
||||
$submit->addButton($save_button);
|
||||
}
|
||||
|
||||
// TODO: A "Create Dashboard Panel" action goes here somewhere once
|
||||
|
|
|
@ -6,16 +6,20 @@ abstract class PhabricatorProfileMenuEngine extends Phobject {
|
|||
private $profileObject;
|
||||
private $customPHID;
|
||||
private $items;
|
||||
private $menuType = self::MENU_GLOBAL;
|
||||
private $defaultItem;
|
||||
private $controller;
|
||||
private $navigation;
|
||||
private $showNavigation = true;
|
||||
private $editMode;
|
||||
private $pageClasses = array();
|
||||
private $showContentCrumbs = true;
|
||||
|
||||
const MENU_GLOBAL = 'global';
|
||||
const MENU_PERSONAL = 'personal';
|
||||
const MENU_COMBINED = 'menu';
|
||||
const ITEM_CUSTOM_DIVIDER = 'engine.divider';
|
||||
const ITEM_MANAGE = 'item.configure';
|
||||
|
||||
const MODE_COMBINED = 'combined';
|
||||
const MODE_GLOBAL = 'global';
|
||||
const MODE_CUSTOM = 'custom';
|
||||
|
||||
public function setViewer(PhabricatorUser $viewer) {
|
||||
$this->viewer = $viewer;
|
||||
|
@ -44,6 +48,21 @@ abstract class PhabricatorProfileMenuEngine extends Phobject {
|
|||
return $this->customPHID;
|
||||
}
|
||||
|
||||
private function getEditModeCustomPHID() {
|
||||
$mode = $this->getEditMode();
|
||||
|
||||
switch ($mode) {
|
||||
case self::MODE_CUSTOM:
|
||||
$custom_phid = $this->getCustomPHID();
|
||||
break;
|
||||
case self::MODE_GLOBAL:
|
||||
$custom_phid = null;
|
||||
break;
|
||||
}
|
||||
|
||||
return $custom_phid;
|
||||
}
|
||||
|
||||
public function setController(PhabricatorController $controller) {
|
||||
$this->controller = $controller;
|
||||
return $this;
|
||||
|
@ -60,19 +79,10 @@ abstract class PhabricatorProfileMenuEngine extends Phobject {
|
|||
}
|
||||
|
||||
public function getDefaultItem() {
|
||||
$this->loadItems();
|
||||
$this->getItems();
|
||||
return $this->defaultItem;
|
||||
}
|
||||
|
||||
public function setMenuType($type) {
|
||||
$this->menuType = $type;
|
||||
return $this;
|
||||
}
|
||||
|
||||
private function getMenuType() {
|
||||
return $this->menuType;
|
||||
}
|
||||
|
||||
public function setShowNavigation($show) {
|
||||
$this->showNavigation = $show;
|
||||
return $this;
|
||||
|
@ -82,6 +92,20 @@ abstract class PhabricatorProfileMenuEngine extends Phobject {
|
|||
return $this->showNavigation;
|
||||
}
|
||||
|
||||
public function addContentPageClass($class) {
|
||||
$this->pageClasses[] = $class;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setShowContentCrumbs($show_content_crumbs) {
|
||||
$this->showContentCrumbs = $show_content_crumbs;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getShowContentCrumbs() {
|
||||
return $this->showContentCrumbs;
|
||||
}
|
||||
|
||||
abstract public function getItemURI($path);
|
||||
abstract protected function isMenuEngineConfigurable();
|
||||
|
||||
|
@ -93,6 +117,10 @@ abstract class PhabricatorProfileMenuEngine extends Phobject {
|
|||
return array();
|
||||
}
|
||||
|
||||
protected function getEditMode() {
|
||||
return $this->editMode;
|
||||
}
|
||||
|
||||
public function buildResponse() {
|
||||
$controller = $this->getController();
|
||||
|
||||
|
@ -106,18 +134,24 @@ abstract class PhabricatorProfileMenuEngine extends Phobject {
|
|||
$item_action = 'view';
|
||||
}
|
||||
|
||||
$is_view = ($item_action == 'view');
|
||||
|
||||
// If the engine is not configurable, don't respond to any of the editing
|
||||
// or configuration routes.
|
||||
if (!$this->isMenuEngineConfigurable()) {
|
||||
switch ($item_action) {
|
||||
case 'view':
|
||||
break;
|
||||
default:
|
||||
if (!$is_view) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
}
|
||||
|
||||
$item_id = $request->getURIData('itemID');
|
||||
|
||||
// If we miss on the MenuEngine route, try the EditEngine route. This will
|
||||
// be populated while editing items.
|
||||
if (!$item_id) {
|
||||
$item_id = $request->getURIData('id');
|
||||
}
|
||||
|
||||
$item_list = $this->getItems();
|
||||
|
||||
$selected_item = null;
|
||||
|
@ -140,7 +174,7 @@ abstract class PhabricatorProfileMenuEngine extends Phobject {
|
|||
}
|
||||
|
||||
if (!$selected_item) {
|
||||
if ($item_action == 'view') {
|
||||
if ($is_view) {
|
||||
$selected_item = $this->getDefaultItem();
|
||||
}
|
||||
}
|
||||
|
@ -171,24 +205,38 @@ abstract class PhabricatorProfileMenuEngine extends Phobject {
|
|||
|
||||
$crumbs = $controller->buildApplicationCrumbsForEditEngine();
|
||||
|
||||
// TODO: This stuff might need a little tweaking at some point, since it
|
||||
// causes "Global" and "Personal" to show up in contexts where they don't
|
||||
// make sense, notably Projects.
|
||||
if ($item_action != 'view') {
|
||||
$navigation->selectFilter('item.configure');
|
||||
switch ($this->getMenuType()) {
|
||||
case 'personal':
|
||||
$crumbs->addTextCrumb(pht('Personal'));
|
||||
break;
|
||||
case 'global':
|
||||
$crumbs->addTextCrumb(pht('Global'));
|
||||
break;
|
||||
if (!$is_view) {
|
||||
$navigation->selectFilter(self::ITEM_MANAGE);
|
||||
|
||||
if ($selected_item) {
|
||||
if ($selected_item->getCustomPHID()) {
|
||||
$edit_mode = 'custom';
|
||||
} else {
|
||||
$edit_mode = 'global';
|
||||
}
|
||||
} else {
|
||||
$edit_mode = $request->getURIData('itemEditMode');
|
||||
}
|
||||
|
||||
$available_modes = $this->getViewerEditModes($viewer);
|
||||
if ($available_modes) {
|
||||
$available_modes = array_fuse($available_modes);
|
||||
if (isset($available_modes[$edit_mode])) {
|
||||
$this->editMode = $edit_mode;
|
||||
} else {
|
||||
if ($item_action != 'configure') {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
}
|
||||
}
|
||||
$page_title = pht('Configure Menu');
|
||||
} else {
|
||||
$page_title = $selected_item->getDisplayName();
|
||||
}
|
||||
|
||||
switch ($item_action) {
|
||||
case 'view':
|
||||
$navigation->selectFilter($selected_item->getItemIdentifier());
|
||||
$navigation->selectFilter($selected_item->getDefaultMenuItemKey());
|
||||
|
||||
$content = $this->buildItemViewContent($selected_item);
|
||||
$crumbs->addTextCrumb($selected_item->getDisplayName());
|
||||
|
@ -197,15 +245,40 @@ abstract class PhabricatorProfileMenuEngine extends Phobject {
|
|||
}
|
||||
break;
|
||||
case 'configure':
|
||||
$content = $this->buildItemConfigureContent($item_list);
|
||||
$mode = $this->getEditMode();
|
||||
if (!$mode) {
|
||||
$crumbs->addTextCrumb(pht('Configure Menu'));
|
||||
$content = $this->buildMenuEditModeContent();
|
||||
} else {
|
||||
if (count($available_modes) > 1) {
|
||||
$crumbs->addTextCrumb(
|
||||
pht('Configure Menu'),
|
||||
$this->getItemURI('configure/'));
|
||||
|
||||
switch ($mode) {
|
||||
case self::MODE_CUSTOM:
|
||||
$crumbs->addTextCrumb(pht('Personal'));
|
||||
break;
|
||||
case self::MODE_GLOBAL:
|
||||
$crumbs->addTextCrumb(pht('Global'));
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
$crumbs->addTextCrumb(pht('Configure Menu'));
|
||||
}
|
||||
$edit_list = $this->loadItems($mode);
|
||||
$content = $this->buildItemConfigureContent($edit_list);
|
||||
}
|
||||
break;
|
||||
case 'reorder':
|
||||
$content = $this->buildItemReorderContent($item_list);
|
||||
$mode = $this->getEditMode();
|
||||
$edit_list = $this->loadItems($mode);
|
||||
$content = $this->buildItemReorderContent($edit_list);
|
||||
break;
|
||||
case 'new':
|
||||
$item_key = $request->getURIData('itemKey');
|
||||
$content = $this->buildItemNewContent($item_key);
|
||||
$mode = $this->getEditMode();
|
||||
$content = $this->buildItemNewContent($item_key, $mode);
|
||||
break;
|
||||
case 'builtin':
|
||||
$content = $this->buildItemBuiltinContent($selected_item);
|
||||
|
@ -214,6 +287,9 @@ abstract class PhabricatorProfileMenuEngine extends Phobject {
|
|||
$content = $this->buildItemHideContent($selected_item);
|
||||
break;
|
||||
case 'default':
|
||||
if (!$this->isMenuEnginePinnable()) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
$content = $this->buildItemDefaultContent(
|
||||
$selected_item,
|
||||
$item_list);
|
||||
|
@ -239,14 +315,23 @@ abstract class PhabricatorProfileMenuEngine extends Phobject {
|
|||
$crumbs->setBorder(true);
|
||||
|
||||
$page = $controller->newPage()
|
||||
->setTitle(pht('Configure Menu'))
|
||||
->setCrumbs($crumbs)
|
||||
->setTitle($page_title)
|
||||
->appendChild($content);
|
||||
|
||||
if (!$is_view || $this->getShowContentCrumbs()) {
|
||||
$page->setCrumbs($crumbs);
|
||||
}
|
||||
|
||||
if ($this->getShowNavigation()) {
|
||||
$page->setNavigation($navigation);
|
||||
}
|
||||
|
||||
if ($is_view) {
|
||||
foreach ($this->pageClasses as $class) {
|
||||
$page->addClass($class);
|
||||
}
|
||||
}
|
||||
|
||||
return $page;
|
||||
}
|
||||
|
||||
|
@ -254,7 +339,6 @@ abstract class PhabricatorProfileMenuEngine extends Phobject {
|
|||
if ($this->navigation) {
|
||||
return $this->navigation;
|
||||
}
|
||||
|
||||
$nav = id(new AphrontSideNavFilterView())
|
||||
->setIsProfileMenu(true)
|
||||
->setBaseURI(new PhutilURI($this->getItemURI('')));
|
||||
|
@ -291,8 +375,8 @@ abstract class PhabricatorProfileMenuEngine extends Phobject {
|
|||
if (count($items) == 1) {
|
||||
$item = head($items);
|
||||
if ($item->getKey() === null) {
|
||||
$item_identifier = $menu_item->getItemIdentifier();
|
||||
$item->setKey($item_identifier);
|
||||
$default_key = $menu_item->getDefaultMenuItemKey();
|
||||
$item->setKey($default_key);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -309,31 +393,30 @@ abstract class PhabricatorProfileMenuEngine extends Phobject {
|
|||
|
||||
private function getItems() {
|
||||
if ($this->items === null) {
|
||||
$this->items = $this->loadItems();
|
||||
$this->items = $this->loadItems(self::MODE_COMBINED);
|
||||
}
|
||||
|
||||
return $this->items;
|
||||
}
|
||||
|
||||
private function loadItems() {
|
||||
private function loadItems($mode) {
|
||||
$viewer = $this->getViewer();
|
||||
$object = $this->getProfileObject();
|
||||
|
||||
$items = $this->loadBuiltinProfileItems();
|
||||
$items = $this->loadBuiltinProfileItems($mode);
|
||||
|
||||
$query = id(new PhabricatorProfileMenuItemConfigurationQuery())
|
||||
->setViewer($viewer)
|
||||
->withProfilePHIDs(array($object->getPHID()));
|
||||
|
||||
$menu_type = $this->getMenuType();
|
||||
switch ($menu_type) {
|
||||
case self::MENU_GLOBAL:
|
||||
switch ($mode) {
|
||||
case self::MODE_GLOBAL:
|
||||
$query->withCustomPHIDs(array(), true);
|
||||
break;
|
||||
case self::MENU_PERSONAL:
|
||||
case self::MODE_CUSTOM:
|
||||
$query->withCustomPHIDs(array($this->getCustomPHID()), false);
|
||||
break;
|
||||
case self::MENU_COMBINED:
|
||||
case self::MODE_COMBINED:
|
||||
$query->withCustomPHIDs(array($this->getCustomPHID()), true);
|
||||
break;
|
||||
}
|
||||
|
@ -369,7 +452,7 @@ abstract class PhabricatorProfileMenuEngine extends Phobject {
|
|||
}
|
||||
}
|
||||
|
||||
$items = $this->arrangeItems($items);
|
||||
$items = $this->arrangeItems($items, $mode);
|
||||
|
||||
// Make sure exactly one valid item is marked as default.
|
||||
$default = null;
|
||||
|
@ -379,10 +462,14 @@ abstract class PhabricatorProfileMenuEngine extends Phobject {
|
|||
continue;
|
||||
}
|
||||
|
||||
// If this engine doesn't support pinning items, don't respect any
|
||||
// setting which might be present in the database.
|
||||
if ($this->isMenuEnginePinnable()) {
|
||||
if ($item->isDefault()) {
|
||||
$default = $item;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($first === null) {
|
||||
$first = $item;
|
||||
|
@ -400,20 +487,19 @@ abstract class PhabricatorProfileMenuEngine extends Phobject {
|
|||
return $items;
|
||||
}
|
||||
|
||||
private function loadBuiltinProfileItems() {
|
||||
private function loadBuiltinProfileItems($mode) {
|
||||
$object = $this->getProfileObject();
|
||||
|
||||
$menu_type = $this->getMenuType();
|
||||
switch ($menu_type) {
|
||||
case self::MENU_GLOBAL:
|
||||
switch ($mode) {
|
||||
case self::MODE_GLOBAL:
|
||||
$builtins = $this->getBuiltinProfileItems($object);
|
||||
break;
|
||||
case self::MENU_PERSONAL:
|
||||
case self::MODE_CUSTOM:
|
||||
$builtins = $this->getBuiltinCustomProfileItems(
|
||||
$object,
|
||||
$this->getCustomPHID());
|
||||
break;
|
||||
case self::MENU_COMBINED:
|
||||
case self::MODE_COMBINED:
|
||||
$builtins = array();
|
||||
$builtins[] = $this->getBuiltinCustomProfileItems(
|
||||
$object,
|
||||
|
@ -490,6 +576,15 @@ abstract class PhabricatorProfileMenuEngine extends Phobject {
|
|||
}
|
||||
|
||||
public function getConfigureURI() {
|
||||
$mode = $this->getEditMode();
|
||||
|
||||
switch ($mode) {
|
||||
case self::MODE_CUSTOM:
|
||||
return $this->getItemURI('configure/custom/');
|
||||
case self::MODE_GLOBAL:
|
||||
return $this->getItemURI('configure/global/');
|
||||
}
|
||||
|
||||
return $this->getItemURI('configure/');
|
||||
}
|
||||
|
||||
|
@ -501,7 +596,8 @@ abstract class PhabricatorProfileMenuEngine extends Phobject {
|
|||
// object the menu appears on. If you're reordering custom items, you only
|
||||
// need to be able to edit the custom object. Currently, the custom object
|
||||
// is always the viewing user's own user object.
|
||||
$custom_phid = $this->getCustomPHID();
|
||||
$custom_phid = $this->getEditModeCustomPHID();
|
||||
|
||||
if (!$custom_phid) {
|
||||
PhabricatorPolicyFilter::requireCapability(
|
||||
$viewer,
|
||||
|
@ -589,11 +685,102 @@ abstract class PhabricatorProfileMenuEngine extends Phobject {
|
|||
->setURI($this->getConfigureURI());
|
||||
}
|
||||
|
||||
private function buildItemViewContent(
|
||||
protected function buildItemViewContent(
|
||||
PhabricatorProfileMenuItemConfiguration $item) {
|
||||
return $item->newPageContent();
|
||||
}
|
||||
|
||||
private function getViewerEditModes() {
|
||||
$modes = array();
|
||||
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
if ($viewer->isLoggedIn() && $this->isMenuEnginePersonalizable()) {
|
||||
$modes[] = self::MODE_CUSTOM;
|
||||
}
|
||||
|
||||
$object = $this->getProfileObject();
|
||||
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
||||
$viewer,
|
||||
$object,
|
||||
PhabricatorPolicyCapability::CAN_EDIT);
|
||||
|
||||
if ($can_edit) {
|
||||
$modes[] = self::MODE_GLOBAL;
|
||||
}
|
||||
|
||||
return $modes;
|
||||
}
|
||||
|
||||
protected function isMenuEnginePersonalizable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this engine support pinning items?
|
||||
*
|
||||
* Personalizable menus disable pinning by default since it creates a number
|
||||
* of weird edge cases without providing many benefits for current menus.
|
||||
*
|
||||
* @return bool True if items may be pinned as default items.
|
||||
*/
|
||||
protected function isMenuEnginePinnable() {
|
||||
return !$this->isMenuEnginePersonalizable();
|
||||
}
|
||||
|
||||
private function buildMenuEditModeContent() {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$modes = $this->getViewerEditModes($viewer);
|
||||
if (!$modes) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
if (count($modes) == 1) {
|
||||
$mode = head($modes);
|
||||
return id(new AphrontRedirectResponse())
|
||||
->setURI($this->getItemURI("configure/{$mode}/"));
|
||||
}
|
||||
|
||||
$menu = id(new PHUIObjectItemListView())
|
||||
->setUser($viewer);
|
||||
|
||||
$modes = array_fuse($modes);
|
||||
|
||||
if (isset($modes['custom'])) {
|
||||
$menu->addItem(
|
||||
id(new PHUIObjectItemView())
|
||||
->setHeader(pht('Personal Menu Items'))
|
||||
->setHref($this->getItemURI('configure/custom/'))
|
||||
->setImageURI($viewer->getProfileImageURI())
|
||||
->addAttribute(pht('Edit the menu for your personal account.')));
|
||||
}
|
||||
|
||||
if (isset($modes['global'])) {
|
||||
$icon = id(new PHUIIconView())
|
||||
->setIcon('fa-globe')
|
||||
->setBackground('bg-blue');
|
||||
|
||||
$menu->addItem(
|
||||
id(new PHUIObjectItemView())
|
||||
->setHeader(pht('Global Menu Items'))
|
||||
->setHref($this->getItemURI('configure/global/'))
|
||||
->setImageIcon($icon)
|
||||
->addAttribute(pht('Edit the global default menu for all users.')));
|
||||
}
|
||||
|
||||
$box = id(new PHUIObjectBoxView())
|
||||
->setObjectList($menu);
|
||||
|
||||
$header = id(new PHUIHeaderView())
|
||||
->setHeader(pht('Manage Menu'))
|
||||
->setHeaderIcon('fa-list');
|
||||
|
||||
return id(new PHUITwoColumnView())
|
||||
->setHeader($header)
|
||||
->setFooter($box);
|
||||
}
|
||||
|
||||
private function buildItemConfigureContent(array $items) {
|
||||
$viewer = $this->getViewer();
|
||||
$object = $this->getProfileObject();
|
||||
|
@ -617,11 +804,13 @@ abstract class PhabricatorProfileMenuEngine extends Phobject {
|
|||
|
||||
$list_id = celerity_generate_unique_node_id();
|
||||
|
||||
$mode = $this->getEditMode();
|
||||
|
||||
Javelin::initBehavior(
|
||||
'reorder-profile-menu-items',
|
||||
array(
|
||||
'listID' => $list_id,
|
||||
'orderURI' => $this->getItemURI('reorder/'),
|
||||
'orderURI' => $this->getItemURI("reorder/{$mode}/"),
|
||||
));
|
||||
|
||||
$list = id(new PHUIObjectItemListView())
|
||||
|
@ -663,14 +852,16 @@ abstract class PhabricatorProfileMenuEngine extends Phobject {
|
|||
$default_uri = $this->getItemURI("default/{$builtin_key}/");
|
||||
}
|
||||
|
||||
$default_text = null;
|
||||
|
||||
if ($this->isMenuEnginePinnable()) {
|
||||
if ($item->isDefault()) {
|
||||
$default_icon = 'fa-thumb-tack green';
|
||||
$default_text = pht('Current Default');
|
||||
} else if ($item->canMakeDefault()) {
|
||||
$default_icon = 'fa-thumb-tack';
|
||||
$default_text = pht('Make Default');
|
||||
} else {
|
||||
$default_text = null;
|
||||
}
|
||||
}
|
||||
|
||||
if ($default_text !== null) {
|
||||
|
@ -739,12 +930,13 @@ abstract class PhabricatorProfileMenuEngine extends Phobject {
|
|||
}
|
||||
|
||||
$item_key = $item_type->getMenuItemKey();
|
||||
$edit_mode = $this->getEditMode();
|
||||
|
||||
$action_list->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setIcon($item_type->getMenuItemTypeIcon())
|
||||
->setName($item_type->getMenuItemTypeName())
|
||||
->setHref($this->getItemURI("new/{$item_key}/"))
|
||||
->setHref($this->getItemURI("new/{$edit_mode}/{$item_key}/"))
|
||||
->setWorkflow(true));
|
||||
}
|
||||
|
||||
|
@ -789,7 +981,7 @@ abstract class PhabricatorProfileMenuEngine extends Phobject {
|
|||
return $view;
|
||||
}
|
||||
|
||||
private function buildItemNewContent($item_key) {
|
||||
private function buildItemNewContent($item_key, $mode) {
|
||||
$item_types = PhabricatorProfileMenuItem::getAllMenuItems();
|
||||
$item_type = idx($item_types, $item_key);
|
||||
if (!$item_type) {
|
||||
|
@ -801,7 +993,8 @@ abstract class PhabricatorProfileMenuEngine extends Phobject {
|
|||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$custom_phid = $this->getCustomPHID();
|
||||
$custom_phid = $this->getEditModeCustomPHID();
|
||||
|
||||
$configuration = PhabricatorProfileMenuItemConfiguration::initializeNewItem(
|
||||
$object,
|
||||
$item_type,
|
||||
|
@ -829,12 +1022,13 @@ abstract class PhabricatorProfileMenuEngine extends Phobject {
|
|||
$viewer = $this->getViewer();
|
||||
$object = $this->getProfileObject();
|
||||
$controller = $this->getController();
|
||||
$custom_phid = $this->getEditModeCustomPHID();
|
||||
|
||||
return id(new PhabricatorProfileMenuEditEngine())
|
||||
->setMenuEngine($this)
|
||||
->setProfileObject($object)
|
||||
->setController($controller)
|
||||
->setCustomPHID($this->getCustomPHID())
|
||||
->setCustomPHID($custom_phid)
|
||||
->buildResponse();
|
||||
}
|
||||
|
||||
|
@ -860,6 +1054,7 @@ abstract class PhabricatorProfileMenuEngine extends Phobject {
|
|||
|
||||
$object = $this->getProfileObject();
|
||||
$controller = $this->getController();
|
||||
$custom_phid = $this->getEditModeCustomPHID();
|
||||
|
||||
return id(new PhabricatorProfileMenuEditEngine())
|
||||
->setIsBuiltin(true)
|
||||
|
@ -867,7 +1062,7 @@ abstract class PhabricatorProfileMenuEngine extends Phobject {
|
|||
->setProfileObject($object)
|
||||
->setNewMenuItemConfiguration($configuration)
|
||||
->setController($controller)
|
||||
->setCustomPHID($this->getCustomPHID())
|
||||
->setCustomPHID($custom_phid)
|
||||
->buildResponse();
|
||||
}
|
||||
|
||||
|
@ -1009,12 +1204,18 @@ abstract class PhabricatorProfileMenuEngine extends Phobject {
|
|||
return PhabricatorProfileMenuItemConfiguration::initializeNewBuiltin();
|
||||
}
|
||||
|
||||
protected function newManageItem() {
|
||||
return $this->newItem()
|
||||
->setBuiltinKey(self::ITEM_MANAGE)
|
||||
->setMenuItemKey(PhabricatorManageProfileMenuItem::MENUITEMKEY);
|
||||
}
|
||||
|
||||
public function adjustDefault($key) {
|
||||
$controller = $this->getController();
|
||||
$request = $controller->getRequest();
|
||||
$viewer = $request->getViewer();
|
||||
|
||||
$items = $this->loadItems();
|
||||
$items = $this->loadItems(self::MODE_COMBINED);
|
||||
|
||||
// To adjust the default item, we first change any existing items that
|
||||
// are marked as defaults to "visible", then make the new default item
|
||||
|
@ -1075,13 +1276,15 @@ abstract class PhabricatorProfileMenuEngine extends Phobject {
|
|||
return $this;
|
||||
}
|
||||
|
||||
private function arrangeItems(array $items) {
|
||||
private function arrangeItems(array $items, $mode) {
|
||||
// Sort the items.
|
||||
$items = msortv($items, 'getSortVector');
|
||||
|
||||
$object = $this->getProfileObject();
|
||||
|
||||
// If we have some global items and some custom items and are in "combined"
|
||||
// mode, put a hard-coded divider item between them.
|
||||
if ($this->getMenuType() == self::MENU_COMBINED) {
|
||||
if ($mode == self::MODE_COMBINED) {
|
||||
$list = array();
|
||||
$seen_custom = false;
|
||||
$seen_global = false;
|
||||
|
@ -1093,6 +1296,7 @@ abstract class PhabricatorProfileMenuEngine extends Phobject {
|
|||
$list[] = $this->newItem()
|
||||
->setBuiltinKey(self::ITEM_CUSTOM_DIVIDER)
|
||||
->setMenuItemKey(PhabricatorDividerProfileMenuItem::MENUITEMKEY)
|
||||
->attachProfileObject($object)
|
||||
->attachMenuItem(
|
||||
new PhabricatorDividerProfileMenuItem());
|
||||
}
|
||||
|
|
|
@ -88,6 +88,12 @@ final class PhabricatorApplicationProfileMenuItem
|
|||
->setName($this->getDisplayName($config))
|
||||
->setIcon($app->getIcon());
|
||||
|
||||
// Don't show tooltip if they've set a custom name
|
||||
$name = $config->getMenuItemProperty('name');
|
||||
if (!strlen($name)) {
|
||||
$item->setTooltip($app->getShortDescription());
|
||||
}
|
||||
|
||||
return array(
|
||||
$item,
|
||||
);
|
||||
|
|
|
@ -89,9 +89,11 @@ final class PhabricatorDashboardProfileMenuItem
|
|||
public function getDisplayName(
|
||||
PhabricatorProfileMenuItemConfiguration $config) {
|
||||
$dashboard = $this->getDashboard();
|
||||
|
||||
if (!$dashboard) {
|
||||
return pht('(Restricted/Invalid Dashboard)');
|
||||
}
|
||||
|
||||
if (strlen($this->getName($config))) {
|
||||
return $this->getName($config);
|
||||
} else {
|
||||
|
|
|
@ -38,6 +38,7 @@ final class PhabricatorDividerProfileMenuItem
|
|||
PhabricatorProfileMenuItemConfiguration $config) {
|
||||
|
||||
$item = $this->newItem()
|
||||
->setType(PHUIListItemView::TYPE_DIVIDER)
|
||||
->addClass('phui-divider');
|
||||
|
||||
return array(
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorLabelProfileMenuItem
|
||||
extends PhabricatorProfileMenuItem {
|
||||
|
||||
const MENUITEMKEY = 'label';
|
||||
const FIELD_NAME = 'name';
|
||||
|
||||
public function getMenuItemTypeIcon() {
|
||||
return 'fa-map-signs';
|
||||
}
|
||||
|
||||
public function getMenuItemTypeName() {
|
||||
return pht('Label');
|
||||
}
|
||||
|
||||
public function canAddToObject($object) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getDisplayName(
|
||||
PhabricatorProfileMenuItemConfiguration $config) {
|
||||
return $this->getLabelName($config);
|
||||
}
|
||||
|
||||
public function buildEditEngineFields(
|
||||
PhabricatorProfileMenuItemConfiguration $config) {
|
||||
return array(
|
||||
id(new PhabricatorTextEditField())
|
||||
->setKey(self::FIELD_NAME)
|
||||
->setLabel(pht('Name'))
|
||||
->setIsRequired(true)
|
||||
->setValue($this->getLabelName($config)),
|
||||
);
|
||||
}
|
||||
|
||||
private function getLabelName(
|
||||
PhabricatorProfileMenuItemConfiguration $config) {
|
||||
return $config->getMenuItemProperty('name');
|
||||
}
|
||||
|
||||
protected function newNavigationMenuItems(
|
||||
PhabricatorProfileMenuItemConfiguration $config) {
|
||||
|
||||
$name = $this->getLabelName($config);
|
||||
|
||||
$item = $this->newItem()
|
||||
->setName($name)
|
||||
->setType(PHUIListItemView::TYPE_LABEL);
|
||||
|
||||
return array(
|
||||
$item,
|
||||
);
|
||||
}
|
||||
|
||||
public function validateTransactions(
|
||||
PhabricatorProfileMenuItemConfiguration $config,
|
||||
$field_key,
|
||||
$value,
|
||||
array $xactions) {
|
||||
|
||||
$viewer = $this->getViewer();
|
||||
$errors = array();
|
||||
|
||||
if ($field_key == self::FIELD_NAME) {
|
||||
if ($this->isEmptyTransaction($value, $xactions)) {
|
||||
$errors[] = $this->newRequiredError(
|
||||
pht('You must choose a label name.'),
|
||||
$field_key);
|
||||
}
|
||||
}
|
||||
|
||||
return $errors;
|
||||
}
|
||||
}
|
|
@ -1,16 +1,16 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorHomeManageProfileMenuItem
|
||||
final class PhabricatorManageProfileMenuItem
|
||||
extends PhabricatorProfileMenuItem {
|
||||
|
||||
const MENUITEMKEY = 'home.manage.menu';
|
||||
const MENUITEMKEY = 'menu.manage';
|
||||
|
||||
public function getMenuItemTypeName() {
|
||||
return pht('Manage Home Menu');
|
||||
return pht('Manage Menu');
|
||||
}
|
||||
|
||||
private function getDefaultName() {
|
||||
return pht('Manage');
|
||||
return pht('Edit Menu');
|
||||
}
|
||||
|
||||
public function canHideMenuItem(
|
||||
|
@ -49,20 +49,20 @@ final class PhabricatorHomeManageProfileMenuItem
|
|||
PhabricatorProfileMenuItemConfiguration $config) {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
if ($viewer->isLoggedIn()) {
|
||||
$admin = $viewer->getIsAdmin();
|
||||
if (!$viewer->isLoggedIn()) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$engine = $this->getEngine();
|
||||
$href = $engine->getItemURI('configure/');
|
||||
|
||||
$name = $this->getDisplayName($config);
|
||||
$icon = 'fa-pencil';
|
||||
$href = '/home/menu/personal/item/configure/';
|
||||
if ($admin) {
|
||||
$href = '/home/menu/';
|
||||
}
|
||||
|
||||
$item = $this->newItem()
|
||||
->setHref($href)
|
||||
->setName($name)
|
||||
->setIcon($icon);
|
||||
}
|
||||
|
||||
return array(
|
||||
$item,
|
|
@ -117,6 +117,7 @@ final class PhabricatorProfileMenuItemConfigurationQuery
|
|||
unset($page[$key]);
|
||||
continue;
|
||||
}
|
||||
|
||||
$item->attachProfileObject($profile);
|
||||
}
|
||||
|
||||
|
|
|
@ -195,6 +195,14 @@ final class PhabricatorProfileMenuItemConfiguration
|
|||
return $this->getBuiltinKey();
|
||||
}
|
||||
|
||||
public function getDefaultMenuItemKey() {
|
||||
if ($this->getBuiltinKey()) {
|
||||
return $this->getBuiltinKey();
|
||||
}
|
||||
|
||||
return $this->getPHID();
|
||||
}
|
||||
|
||||
public function newPageContent() {
|
||||
return $this->getMenuItem()->newPageContent($this);
|
||||
}
|
||||
|
|
|
@ -1,223 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorHomePreferencesSettingsPanel
|
||||
extends PhabricatorSettingsPanel {
|
||||
|
||||
public function getPanelKey() {
|
||||
return 'home';
|
||||
}
|
||||
|
||||
public function getPanelName() {
|
||||
return pht('Home Page');
|
||||
}
|
||||
|
||||
public function getPanelGroupKey() {
|
||||
return PhabricatorSettingsApplicationsPanelGroup::PANELGROUPKEY;
|
||||
}
|
||||
|
||||
public function isTemplatePanel() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function processRequest(AphrontRequest $request) {
|
||||
$viewer = $this->getViewer();
|
||||
$preferences = $this->getPreferences();
|
||||
|
||||
$pinned_key = PhabricatorPinnedApplicationsSetting::SETTINGKEY;
|
||||
$pinned = $preferences->getSettingValue($pinned_key);
|
||||
|
||||
$apps = id(new PhabricatorApplicationQuery())
|
||||
->setViewer($viewer)
|
||||
->withInstalled(true)
|
||||
->withUnlisted(false)
|
||||
->withLaunchable(true)
|
||||
->execute();
|
||||
|
||||
$app_list = array();
|
||||
foreach ($pinned as $app) {
|
||||
if (isset($apps[$app])) {
|
||||
$app_list[$app] = $apps[$app];
|
||||
}
|
||||
}
|
||||
|
||||
if ($request->getBool('reset')) {
|
||||
if ($request->isFormPost()) {
|
||||
$this->writePinnedApplications($preferences, null);
|
||||
return id(new AphrontRedirectResponse())
|
||||
->setURI($this->getPanelURI());
|
||||
}
|
||||
|
||||
return $this->newDialog()
|
||||
->setTitle(pht('Reset Applications'))
|
||||
->addHiddenInput('reset', 'true')
|
||||
->appendParagraph(
|
||||
pht('Reset pinned applications to their defaults?'))
|
||||
->addSubmitButton(pht('Reset Applications'))
|
||||
->addCancelButton($this->getPanelURI());
|
||||
}
|
||||
|
||||
|
||||
if ($request->getBool('add')) {
|
||||
$options = array();
|
||||
foreach ($apps as $app) {
|
||||
$options[get_class($app)] = $app->getName();
|
||||
}
|
||||
asort($options);
|
||||
|
||||
unset($options['PhabricatorApplicationsApplication']);
|
||||
|
||||
if ($request->isFormPost()) {
|
||||
$pins = $request->getArr('pin');
|
||||
$phid = head($pins);
|
||||
$app = id(new PhabricatorApplicationQuery())
|
||||
->setViewer($viewer)
|
||||
->withPHIDs(array($phid))
|
||||
->executeOne();
|
||||
if ($app) {
|
||||
$pin = get_class($app);
|
||||
} else {
|
||||
// This likely means the user submitted an empty form
|
||||
// which will cause nothing to happen.
|
||||
$pin = '';
|
||||
}
|
||||
if (isset($options[$pin]) && !in_array($pin, $pinned)) {
|
||||
$pinned[] = $pin;
|
||||
|
||||
$this->writePinnedApplications($preferences, $pinned);
|
||||
|
||||
return id(new AphrontRedirectResponse())
|
||||
->setURI($this->getPanelURI());
|
||||
}
|
||||
}
|
||||
|
||||
$options_control = id(new AphrontFormTokenizerControl())
|
||||
->setName('pin')
|
||||
->setLabel(pht('Application'))
|
||||
->setDatasource(new PhabricatorApplicationDatasource())
|
||||
->setLimit(1);
|
||||
|
||||
$form = id(new AphrontFormView())
|
||||
->setViewer($viewer)
|
||||
->addHiddenInput('add', 'true')
|
||||
->appendRemarkupInstructions(
|
||||
pht('Choose an application to pin to your home page.'))
|
||||
->appendControl($options_control);
|
||||
|
||||
return $this->newDialog()
|
||||
->setWidth(AphrontDialogView::WIDTH_FORM)
|
||||
->setTitle(pht('Pin Application'))
|
||||
->appendChild($form->buildLayoutView())
|
||||
->addSubmitButton(pht('Pin Application'))
|
||||
->addCancelButton($this->getPanelURI());
|
||||
}
|
||||
|
||||
$unpin = $request->getStr('unpin');
|
||||
if ($unpin) {
|
||||
$app = idx($apps, $unpin);
|
||||
if ($app) {
|
||||
if ($request->isFormPost()) {
|
||||
$pinned = array_diff($pinned, array($unpin));
|
||||
|
||||
$this->writePinnedApplications($preferences, $pinned);
|
||||
|
||||
return id(new AphrontRedirectResponse())
|
||||
->setURI($this->getPanelURI());
|
||||
}
|
||||
|
||||
return $this->newDialog()
|
||||
->setTitle(pht('Unpin Application'))
|
||||
->addHiddenInput('unpin', $unpin)
|
||||
->appendParagraph(
|
||||
pht(
|
||||
'Unpin the %s application from your home page?',
|
||||
phutil_tag('strong', array(), $app->getName())))
|
||||
->addSubmitButton(pht('Unpin Application'))
|
||||
->addCancelButton($this->getPanelURI());
|
||||
}
|
||||
}
|
||||
|
||||
$order = $request->getStrList('order');
|
||||
if ($order && $request->validateCSRF()) {
|
||||
$this->writePinnedApplications($preferences, $order);
|
||||
|
||||
return id(new AphrontRedirectResponse())
|
||||
->setURI($this->getPanelURI());
|
||||
}
|
||||
|
||||
$list_id = celerity_generate_unique_node_id();
|
||||
|
||||
$list = id(new PHUIObjectItemListView())
|
||||
->setViewer($viewer)
|
||||
->setID($list_id)
|
||||
->setDrag(true);
|
||||
|
||||
Javelin::initBehavior(
|
||||
'reorder-applications',
|
||||
array(
|
||||
'listID' => $list_id,
|
||||
'panelURI' => $this->getPanelURI(),
|
||||
));
|
||||
|
||||
foreach ($app_list as $key => $application) {
|
||||
if ($key == 'PhabricatorApplicationsApplication') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$icon = $application->getIcon();
|
||||
if (!$icon) {
|
||||
$icon = 'fa-globe';
|
||||
}
|
||||
|
||||
$item = id(new PHUIObjectItemView())
|
||||
->setHeader($application->getName())
|
||||
->setImageIcon($icon)
|
||||
->setGrippable(true);
|
||||
|
||||
$item->addAction(
|
||||
id(new PHUIListItemView())
|
||||
->setIcon('fa-times')
|
||||
->setHref($this->getPanelURI().'?unpin='.$key)
|
||||
->setWorkflow(true));
|
||||
|
||||
$item->addSigil('pinned-application');
|
||||
$item->setMetadata(
|
||||
array(
|
||||
'applicationClass' => $key,
|
||||
));
|
||||
|
||||
$list->addItem($item);
|
||||
}
|
||||
|
||||
$header = id(new PHUIHeaderView())
|
||||
->setHeader(pht('Pinned Applications'))
|
||||
->addActionLink(
|
||||
id(new PHUIButtonView())
|
||||
->setTag('a')
|
||||
->setText(pht('Pin Application'))
|
||||
->setHref($this->getPanelURI().'?add=true')
|
||||
->setWorkflow(true)
|
||||
->setIcon('fa-thumb-tack'))
|
||||
->addActionLink(
|
||||
id(new PHUIButtonView())
|
||||
->setTag('a')
|
||||
->setText(pht('Reset to Defaults'))
|
||||
->setHref($this->getPanelURI().'?reset=true')
|
||||
->setWorkflow(true)
|
||||
->setIcon('fa-recycle'));
|
||||
|
||||
$box = id(new PHUIObjectBoxView())
|
||||
->setHeader($header)
|
||||
->setObjectList($list);
|
||||
|
||||
return $box;
|
||||
}
|
||||
|
||||
private function writePinnedApplications(
|
||||
PhabricatorUserPreferences $preferences,
|
||||
$pinned) {
|
||||
|
||||
$pinned_key = PhabricatorPinnedApplicationsSetting::SETTINGKEY;
|
||||
$this->writeSetting($preferences, $pinned_key, $pinned);
|
||||
}
|
||||
|
||||
}
|
|
@ -156,6 +156,46 @@ Audit Tips
|
|||
- Press "?" to view keyboard shortcuts.
|
||||
|
||||
|
||||
Audit Maintenance
|
||||
=================
|
||||
|
||||
The `bin/audit` command allows you to perform several maintenance operations.
|
||||
Get more information about a command by running:
|
||||
|
||||
```
|
||||
phabricator/ $ ./bin/audit help <command>
|
||||
```
|
||||
|
||||
Supported operations are:
|
||||
|
||||
**Delete Audits**: Delete audits that match certain parameters with
|
||||
`bin/audit delete`.
|
||||
|
||||
You can use this command to forcibly delete requests which may have triggered
|
||||
incorrectly (for example, because a package or Herald rule was configured in an
|
||||
overbroad way).
|
||||
|
||||
After deleting audits, you may want to run `bin/audit synchronize` to
|
||||
synchronize audit state.
|
||||
|
||||
**Synchronize Audit State**: Synchronize the audit state of commits to the
|
||||
current open audit requests with `bin/audit synchronize`.
|
||||
|
||||
Normally, overall audit state is automatically kept up to date as changes are
|
||||
made to an audit. However, if you delete audits or manually update the database
|
||||
to make changes to audit request state, the state of corresponding commits may
|
||||
no longer be correct.
|
||||
|
||||
This command will update commits so their overall audit state reflects the
|
||||
cumulative state of their actual audit requests.
|
||||
|
||||
**Update Owners Package Membership**: Update which Owners packages commits
|
||||
belong to with `bin/audit update-owners`.
|
||||
|
||||
Normally, commits are automatically associated with packages when they are
|
||||
imported. You can use this command to manually rebuild this association if
|
||||
you run into problems with it.
|
||||
|
||||
Next Steps
|
||||
==========
|
||||
|
||||
|
|
|
@ -16,21 +16,12 @@ Supported Applications
|
|||
|
||||
These applications currently support profile menus:
|
||||
|
||||
| Application | Support |
|
||||
|-----|-----|
|
||||
| Projects | Full |
|
||||
| People | //Read-Only// |
|
||||
|
||||
|
||||
Collapsing and Expanding
|
||||
========================
|
||||
|
||||
To collapse a full-width profile menu, click
|
||||
{nav icon="angle-left", name="Collapse"}. To expand a narrow menu, click
|
||||
{nav icon="angle-right", name="Expand"}.
|
||||
|
||||
If you're logged in, this setting is sticky, and all menus will respect your
|
||||
preference.
|
||||
| Application | Customization | Support |
|
||||
|-----|-----|-----|
|
||||
| Home | Global/Personal | Full |
|
||||
| Projects | Per Project | Full |
|
||||
| Favorites Menu | Global/Personal | Full |
|
||||
| People | None | //Read-Only// |
|
||||
|
||||
|
||||
Editing Menus
|
||||
|
@ -40,7 +31,10 @@ You can only edit an object's menu if you can edit the object. For example, you
|
|||
must have permission to edit a project in order to reconfigure the menu for the
|
||||
project.
|
||||
|
||||
To edit a menu, click {nav icon="cogs", name="Manage"} in the menu, then click
|
||||
To edit a menu, click {nav icon="cogs", name="Manage"} or {nav icon="pencil",
|
||||
name="Edit ..."} in the menu itself. If you are an administrator and the
|
||||
application supports Global/Personal customization, you'll have the option
|
||||
of editing either the Global settings or your own Personal menu, otherwise click
|
||||
{nav icon="th-list", name="Edit Menu"}. This brings you to the menu
|
||||
configuration interface which allows you to add and remove items, reorder the
|
||||
menu, edit existing items, and choose a default item.
|
||||
|
@ -94,7 +88,7 @@ To remove items, click the {nav icon="times", name="Delete"} action.
|
|||
Builtin items can not be deleted and have a
|
||||
{nav icon="times", name="Disable"} action instead, which will hide them but
|
||||
not delete them. You an re-enable a disabled item with the
|
||||
{nav icon="plus', name="Enable"} action.
|
||||
{nav icon="plus", name="Enable"} action.
|
||||
|
||||
A few items can not be hidden or deleted. For example, the
|
||||
{nav icon="cogs", name="Manage"} item must always be available in the menu
|
||||
|
@ -130,17 +124,36 @@ When you add items, you can choose between different types of items to add.
|
|||
Which item types are available depends on what sort of object you are editing
|
||||
the menu for, but most objects support these items:
|
||||
|
||||
- {icon link} **Link**: Allows you to create an item which links to
|
||||
somewhere else in Phabricator, or to an external site.
|
||||
|
||||
- {icon minus} **Divider**: Adds a visual separator to the menu. This is
|
||||
purely cosmetic.
|
||||
- {icon coffee} **Motivator**: Motivate your employees with inspirational
|
||||
quotes. A new quote every day!
|
||||
- {icon map-marker} **Label**: Lets you label sections of menu items.
|
||||
This is also purely cosmetic.
|
||||
- {icon link} **Link**: Allows you to create an item which links to
|
||||
somewhere else in Phabricator, or to an external site.
|
||||
- {icon plus} **Form**: Provides quick access to custom and built-in forms
|
||||
from any application that supports EditEngine.
|
||||
- {icon briefcase} **Projects**: Provides quick access to a project.
|
||||
- {icon globe} **Applications**: Provides quick access to your favorite
|
||||
applications. Can be renamed.
|
||||
- {icon tachometer} **Dashboard**: Provides quick access to your favorite
|
||||
dashboard. These items will display with the current nav on the item
|
||||
you've attached it to.
|
||||
|
||||
|
||||
To learn more about how an item works, try adding it. You can always delete
|
||||
it later if it doesn't do what you wanted.
|
||||
|
||||
|
||||
Dashboard Integration
|
||||
=====================
|
||||
|
||||
Dashboards are directly integrated with Profile Menus. If you add a Dashboard
|
||||
to a Project or to a Home menu, that Dashboard will be presented in the
|
||||
context of that menu. This allows customization of different pages of content
|
||||
without having the user leave Home or the Project.
|
||||
|
||||
|
||||
Writing New Item Types
|
||||
======================
|
||||
|
||||
|
|
|
@ -1588,6 +1588,26 @@ final class PhabricatorUSEnglishTranslation
|
|||
),
|
||||
),
|
||||
|
||||
'%s added %s auditor(s): %s.' => array(
|
||||
array(
|
||||
'%s added an auditor: %3$s.',
|
||||
'%s added auditors: %3$s.',
|
||||
),
|
||||
),
|
||||
|
||||
'%s removed %s auditor(s): %s.' => array(
|
||||
array(
|
||||
'%s removed an auditor: %3$s.',
|
||||
'%s removed auditors: %3$s.',
|
||||
),
|
||||
),
|
||||
|
||||
'%s edited %s auditor(s), removed %s: %s; added %s: %s.' => array(
|
||||
array(
|
||||
'%s edited auditors, removed: %4$s; added: %6$s.',
|
||||
),
|
||||
),
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,5 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* @phutil-external-symbol function recaptcha_get_html
|
||||
* @phutil-external-symbol function recaptcha_check_answer
|
||||
*/
|
||||
final class AphrontFormRecaptchaControl extends AphrontFormControl {
|
||||
|
||||
protected function getCustomControlClass() {
|
||||
|
@ -19,13 +14,8 @@ final class AphrontFormRecaptchaControl extends AphrontFormControl {
|
|||
return PhabricatorEnv::getEnvConfig('recaptcha.enabled');
|
||||
}
|
||||
|
||||
private static function requireLib() {
|
||||
$root = phutil_get_library_root('phabricator');
|
||||
require_once dirname($root).'/externals/recaptcha/recaptchalib.php';
|
||||
}
|
||||
|
||||
public static function hasCaptchaResponse(AphrontRequest $request) {
|
||||
return $request->getBool('recaptcha_response_field');
|
||||
return $request->getBool('g-recaptcha-response');
|
||||
}
|
||||
|
||||
public static function processCaptcha(AphrontRequest $request) {
|
||||
|
@ -33,30 +23,35 @@ final class AphrontFormRecaptchaControl extends AphrontFormControl {
|
|||
return true;
|
||||
}
|
||||
|
||||
self::requireLib();
|
||||
$uri = 'https://www.google.com/recaptcha/api/siteverify';
|
||||
$params = array(
|
||||
'secret' => PhabricatorEnv::getEnvConfig('recaptcha.private-key'),
|
||||
'response' => $request->getStr('g-recaptcha-response'),
|
||||
'remoteip' => $request->getRemoteAddress(),
|
||||
);
|
||||
|
||||
$challenge = $request->getStr('recaptcha_challenge_field');
|
||||
$response = $request->getStr('recaptcha_response_field');
|
||||
$resp = recaptcha_check_answer(
|
||||
PhabricatorEnv::getEnvConfig('recaptcha.private-key'),
|
||||
$_SERVER['REMOTE_ADDR'],
|
||||
$challenge,
|
||||
$response);
|
||||
list($body) = id(new HTTPSFuture($uri, $params))
|
||||
->setMethod('POST')
|
||||
->resolvex();
|
||||
|
||||
return (bool)@$resp->is_valid;
|
||||
$json = phutil_json_decode($body);
|
||||
return (bool)idx($json, 'success');
|
||||
}
|
||||
|
||||
protected function renderInput() {
|
||||
self::requireLib();
|
||||
$js = 'https://www.google.com/recaptcha/api.js';
|
||||
$pubkey = PhabricatorEnv::getEnvConfig('recaptcha.public-key');
|
||||
|
||||
$uri = new PhutilURI(PhabricatorEnv::getEnvConfig('phabricator.base-uri'));
|
||||
$protocol = $uri->getProtocol();
|
||||
$use_ssl = ($protocol == 'https');
|
||||
return array(
|
||||
phutil_tag('div', array(
|
||||
'class' => 'g-recaptcha',
|
||||
'data-sitekey' => $pubkey,
|
||||
)),
|
||||
|
||||
return phutil_safe_html(recaptcha_get_html(
|
||||
PhabricatorEnv::getEnvConfig('recaptcha.public-key'),
|
||||
$error = null,
|
||||
$use_ssl));
|
||||
phutil_tag('script', array(
|
||||
'type' => 'text/javascript',
|
||||
'src' => $js,
|
||||
)),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,20 +2,23 @@
|
|||
|
||||
final class AphrontFormSubmitControl extends AphrontFormControl {
|
||||
|
||||
private $cancelButton;
|
||||
private $buttons = array();
|
||||
|
||||
public function addCancelButton($href, $label = null) {
|
||||
if (!$label) {
|
||||
$label = pht('Cancel');
|
||||
}
|
||||
$button = id(new PHUIButtonView())
|
||||
->setTag('a')
|
||||
->setHref($href)
|
||||
->setText($label)
|
||||
->setColor(PHUIButtonView::GREY);
|
||||
$this->addButton($button);
|
||||
return $this;
|
||||
}
|
||||
|
||||
$this->cancelButton = phutil_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => $href,
|
||||
'class' => 'button grey',
|
||||
),
|
||||
$label);
|
||||
public function addButton(PHUIButtonView $button) {
|
||||
$this->buttons[] = $button;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
@ -38,7 +41,7 @@ final class AphrontFormSubmitControl extends AphrontFormControl {
|
|||
|
||||
return array(
|
||||
$submit_button,
|
||||
$this->cancelButton,
|
||||
$this->buttons,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -204,7 +204,6 @@ final class AphrontSideNavFilterView extends AphrontView {
|
|||
|
||||
private function renderFlexNav() {
|
||||
require_celerity_resource('phabricator-nav-view-css');
|
||||
require_celerity_resource('phui-profile-menu-css');
|
||||
|
||||
$nav_classes = array();
|
||||
$nav_classes[] = 'phabricator-nav';
|
||||
|
@ -310,7 +309,7 @@ final class AphrontSideNavFilterView extends AphrontView {
|
|||
$classes[] = 'phui-navigation-shell';
|
||||
|
||||
if ($this->getIsProfileMenu()) {
|
||||
$classes[] = 'phui-profile-menu';
|
||||
$classes[] = 'phui-profile-menu phui-basic-nav';
|
||||
} else {
|
||||
$classes[] = 'phui-basic-nav';
|
||||
}
|
||||
|
|
|
@ -507,6 +507,7 @@ final class PHUIIconView extends AphrontTagView {
|
|||
'fa-pied-piper-square',
|
||||
'fa-pied-piper',
|
||||
'fa-pied-piper-alt',
|
||||
'fa-pied-piper-pp',
|
||||
'fa-drupal',
|
||||
'fa-joomla',
|
||||
'fa-language',
|
||||
|
@ -781,6 +782,69 @@ final class PHUIIconView extends AphrontTagView {
|
|||
'fa-snapchat',
|
||||
'fa-snapchat-ghost',
|
||||
'fa-snapchat-square',
|
||||
'fa-first-order',
|
||||
'fa-yoast',
|
||||
'fa-themeisle',
|
||||
'fa-google-plus-circle',
|
||||
'fa-google-plus-official',
|
||||
'fa-fa',
|
||||
'fa-font-awesome',
|
||||
'fa-handshake-o',
|
||||
'fa-envelope-open',
|
||||
'fa-envelope-open-o',
|
||||
'fa-linode',
|
||||
'fa-address-book',
|
||||
'fa-address-book-o',
|
||||
'fa-vcard',
|
||||
'fa-address-card',
|
||||
'fa-vcard-o',
|
||||
'fa-address-card-o',
|
||||
'fa-user-circle',
|
||||
'fa-user-circle-o',
|
||||
'fa-user-o:before',
|
||||
'fa-id-badge',
|
||||
'fa-drivers-license',
|
||||
'fa-id-card',
|
||||
'fa-drivers-license-o',
|
||||
'fa-id-card-o',
|
||||
'fa-quora',
|
||||
'fa-free-code-camp',
|
||||
'fa-telegram',
|
||||
'fa-thermometer-4',
|
||||
'fa-thermometer',
|
||||
'fa-thermometer-full',
|
||||
'fa-thermometer-3',
|
||||
'fa-thermometer-three-quarters',
|
||||
'fa-thermometer-2',
|
||||
'fa-thermometer-half',
|
||||
'fa-thermometer-1',
|
||||
'fa-thermometer-quarter',
|
||||
'fa-thermometer-0:',
|
||||
'fa-thermometer-empty',
|
||||
'fa-shower',
|
||||
'fa-bathtub',
|
||||
'fa-s15',
|
||||
'fa-bath',
|
||||
'fa-podcast',
|
||||
'fa-window-maximize',
|
||||
'fa-window-minimize',
|
||||
'fa-window-restore',
|
||||
'fa-times-rectangle',
|
||||
'fa-window-close',
|
||||
'fa-times-rectangle-o',
|
||||
'fa-window-close-o',
|
||||
'fa-bandcamp',
|
||||
'fa-grav',
|
||||
'fa-etsy',
|
||||
'fa-imdb',
|
||||
'fa-ravelry',
|
||||
'fa-eercast',
|
||||
'fa-microchip',
|
||||
'fa-snowflake-o',
|
||||
'fa-superpowers',
|
||||
'fa-wpexplorer',
|
||||
'fa-meetup',
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ final class PHUIListItemView extends AphrontTagView {
|
|||
private $hideInApplicationMenu;
|
||||
private $icons = array();
|
||||
private $openInNewWindow = false;
|
||||
private $tooltip;
|
||||
|
||||
public function setOpenInNewWindow($open_in_new_window) {
|
||||
$this->openInNewWindow = $open_in_new_window;
|
||||
|
@ -176,6 +177,11 @@ final class PHUIListItemView extends AphrontTagView {
|
|||
return $this->icons;
|
||||
}
|
||||
|
||||
public function setTooltip($tooltip) {
|
||||
$this->tooltip = $tooltip;
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function getTagName() {
|
||||
return 'li';
|
||||
}
|
||||
|
@ -185,7 +191,7 @@ final class PHUIListItemView extends AphrontTagView {
|
|||
$classes[] = 'phui-list-item-view';
|
||||
$classes[] = 'phui-list-item-'.$this->type;
|
||||
|
||||
if ($this->icon) {
|
||||
if ($this->icon || $this->profileImage) {
|
||||
$classes[] = 'phui-list-item-has-icon';
|
||||
}
|
||||
|
||||
|
@ -230,6 +236,16 @@ final class PHUIListItemView extends AphrontTagView {
|
|||
'align' => 'E',
|
||||
);
|
||||
} else {
|
||||
if ($this->tooltip) {
|
||||
Javelin::initBehavior('phabricator-tooltips');
|
||||
$sigil = 'has-tooltip';
|
||||
$meta = array(
|
||||
'tip' => $this->tooltip,
|
||||
'align' => 'E',
|
||||
'size' => 300,
|
||||
);
|
||||
}
|
||||
|
||||
$external = null;
|
||||
if ($this->isExternal) {
|
||||
$external = " \xE2\x86\x97";
|
||||
|
|
|
@ -210,7 +210,9 @@ th.aphront-table-view-sortable-selected {
|
|||
padding: 0px;
|
||||
}
|
||||
|
||||
|
||||
.aphront-table-view td.icon + td.icon {
|
||||
padding-left: 8px;
|
||||
}
|
||||
|
||||
div.single-display-line-bounds {
|
||||
width: 100%;
|
||||
|
|
|
@ -7,15 +7,40 @@
|
|||
padding: 5px;
|
||||
}
|
||||
|
||||
.jx-tooltip-appear {
|
||||
animation: 0.5s tooltip-appear;
|
||||
|
||||
/* Without this, there's a nasty pop-in effect at the end of the animation
|
||||
when Safari changes font smoothing. The text becomes visibly more bold
|
||||
after the last frame of animation. */
|
||||
-webkit-font-smoothing: subpixel-antialiased;
|
||||
}
|
||||
|
||||
@keyframes tooltip-appear {
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.jx-tooltip-hidden {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.jx-tooltip-inner {
|
||||
position: relative;
|
||||
background: rgba({$alphablack}, .9);
|
||||
background: #000;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.jx-tooltip {
|
||||
color: #f9f9f9;
|
||||
color: #fff;
|
||||
font-size: {$normalfontsize};
|
||||
-webkit-font-smoothing: antialiased;
|
||||
font-weight: bold;
|
||||
padding: 6px 8px;
|
||||
overflow: hidden;
|
||||
white-space: pre-wrap;
|
||||
|
|
|
@ -164,10 +164,7 @@
|
|||
right: 0;
|
||||
position: absolute;
|
||||
font-size: {$normalfontsize};
|
||||
border-width: 1px;
|
||||
border-color: {$lightblueborder};
|
||||
border-radius: 3px;
|
||||
border-style: solid;
|
||||
border: none;
|
||||
background-color: #fff;
|
||||
height: 28px;
|
||||
padding: 3px 28px 3px 52px;
|
||||
|
@ -180,13 +177,13 @@
|
|||
font-size: {$biggestfontsize};
|
||||
width: 100%;
|
||||
padding-left: 50px;
|
||||
border: 1px solid {$lightblueborder};
|
||||
}
|
||||
|
||||
.phabricator-main-menu .phabricator-main-menu-search input:focus {
|
||||
background: #fff;
|
||||
opacity: 1;
|
||||
color: {$darkbluetext};
|
||||
border-color: {$sky};
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,103 +0,0 @@
|
|||
/**
|
||||
* @provides phabricator-application-launch-view-css
|
||||
*/
|
||||
|
||||
|
||||
/* - Application List ----------------------------------------------------------
|
||||
|
||||
Spacing container for the list of large application buttons.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
.application-tile-group {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
|
||||
/* - Application Launch Button -------------------------------------------------
|
||||
|
||||
Spacing container for the list of large application buttons.
|
||||
|
||||
*/
|
||||
|
||||
a.phabricator-application-launch-container,
|
||||
div.phabricator-application-launch-container {
|
||||
display: block;
|
||||
float: left;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
text-decoration: none;
|
||||
width: 100%;
|
||||
border-top-right-radius: 3px;
|
||||
border-bottom-right-radius: 3px;
|
||||
padding: 4px 0;
|
||||
}
|
||||
|
||||
.device-phone div.phabricator-application-launch-container {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.phabricator-application-launch-icon {
|
||||
position: absolute;
|
||||
width: 38px;
|
||||
height: 18px;
|
||||
top: 6px;
|
||||
left: 0;
|
||||
font-size: 18px;
|
||||
text-align: center;
|
||||
vertical-align: bottom;
|
||||
color: {$darkbluetext};
|
||||
text-shadow: {$whitetextshadow};
|
||||
}
|
||||
|
||||
.device-desktop a.phabricator-application-launch-container:hover {
|
||||
background-color: rgba({$alphablack},.07);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.device-desktop a.phabricator-application-launch-container:hover
|
||||
.phabricator-application-launch-icon {
|
||||
color: {$sky};
|
||||
}
|
||||
|
||||
.phabricator-application-launch-name {
|
||||
display: block;
|
||||
font-weight: bold;
|
||||
color: {$darkbluetext};
|
||||
font-size: {$normalfontsize};
|
||||
margin-left: 36px;
|
||||
}
|
||||
|
||||
.phabricator-application-launch-description {
|
||||
color: {$bluetext};
|
||||
font-size: {$smallestfontsize};
|
||||
margin-left: 36px;
|
||||
text-overflow: ellipsis;
|
||||
width: 150px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
display: inline-block;
|
||||
padding: 2px 0 0 0;
|
||||
}
|
||||
|
||||
.phabricator-application-launch-attention {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
right: 8px;
|
||||
color: {$darkbluetext};
|
||||
font-weight: bold;
|
||||
font-size: {$smallerfontsize};
|
||||
}
|
||||
|
||||
.phabricator-application-attention-count {
|
||||
color: {$fire};
|
||||
}
|
||||
|
||||
a.phabricator-application-launch-phone-only {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.device-phone a.phabricator-application-launch-phone-only {
|
||||
display: block;
|
||||
}
|
|
@ -5,7 +5,7 @@
|
|||
/*--- Header Colors ----------------------------------------------------------*/
|
||||
|
||||
.phui-theme-blindigo .phabricator-main-menu-background {
|
||||
background: #41506e;
|
||||
background: #4a5f88;
|
||||
}
|
||||
|
||||
.phui-theme-dark .phabricator-main-menu-background {
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
padding-bottom: 1px;
|
||||
padding-left: 8px;
|
||||
width: 100%;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.diffusion-browse-type-form {
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
/**
|
||||
* @provides people-picture-menu-item-css
|
||||
*/
|
||||
|
||||
.people-menu-image {
|
||||
width: 160px;
|
||||
height: 160px;
|
||||
border: 1px solid {$thinblueborder};
|
||||
}
|
||||
|
||||
.people-menu-image-container {
|
||||
background: #fff;
|
||||
padding: 4px;
|
||||
border-radius: 3px;
|
||||
border: 1px solid {$lightblueborder};
|
||||
margin: 4px 0px 16px 20px;
|
||||
display: inline-block;
|
||||
}
|
|
@ -87,3 +87,11 @@
|
|||
.profile-no-badges {
|
||||
padding: 24px 0;
|
||||
}
|
||||
|
||||
.people-profile-header.phui-profile-header .phui-header-col1 {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.device .people-profile-header.phui-profile-header .phui-header-col1 {
|
||||
display: table-cell;
|
||||
}
|
||||
|
|
|
@ -6,6 +6,10 @@
|
|||
background-color: #fff;
|
||||
}
|
||||
|
||||
.application-search-view .phui-crumbs-view {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.application-search-view .application-search-results.phui-object-box {
|
||||
margin: 0;
|
||||
padding: 0 16px 24px;
|
||||
|
@ -17,7 +21,7 @@
|
|||
}
|
||||
|
||||
.application-search-view .application-search-results .phui-profile-header {
|
||||
padding: 16px 8px;
|
||||
padding: 22px 8px;
|
||||
border-bottom: 1px solid {$thinblueborder};
|
||||
}
|
||||
|
||||
|
|
167
webroot/rsrc/css/font/font-awesome.css
vendored
167
webroot/rsrc/css/font/font-awesome.css
vendored
|
@ -3,15 +3,15 @@
|
|||
*/
|
||||
|
||||
/*!
|
||||
* Font Awesome 4.6.0 by @davegandy - http://fontawesome.io - @fontawesome
|
||||
* Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome
|
||||
* License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
|
||||
*/
|
||||
/* FONT PATH
|
||||
* -------------------------- */
|
||||
@font-face {
|
||||
font-family: 'FontAwesome';
|
||||
src: url('/rsrc/externals/font/fontawesome/fontawesome-webfont.eot?v=4.6.0');
|
||||
src: url('/rsrc/externals/font/fontawesome/fontawesome-webfont.eot?#iefix&v=4.6.0') format('embedded-opentype'), url('/rsrc/externals/font/fontawesome/fontawesome-webfont.woff2?v=4.6.0') format('woff2'), url('/rsrc/externals/font/fontawesome/fontawesome-webfont.woff?v=4.6.0') format('woff'), url('/rsrc/externals/font/fontawesome/fontawesome-webfont.ttf?v=4.6.0') format('truetype'), url('/rsrc/externals/font/fontawesome/fontawesome-webfont.svg?v=4.6.0#fontawesomeregular') format('svg');
|
||||
src: url('/rsrc/externals/font/fontawesome/fontawesome-webfont.eot?v=4.7.0');
|
||||
src: url('/rsrc/externals/font/fontawesome/fontawesome-webfont.eot?#iefix&v=4.7.0') format('embedded-opentype'), url('/rsrc/externals/font/fontawesome/fontawesome-webfont.woff2?v=4.7.0') format('woff2'), url('/rsrc/externals/font/fontawesome/fontawesome-webfont.woff?v=4.7.0') format('woff'), url('/rsrc/externals/font/fontawesome/fontawesome-webfont.ttf?v=4.7.0') format('truetype'), url('/rsrc/externals/font/fontawesome/fontawesome-webfont.svg?v=4.7.0#fontawesomeregular') format('svg');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
@ -1246,7 +1246,7 @@
|
|||
.fa-digg:before {
|
||||
content: "\f1a6";
|
||||
}
|
||||
.fa-pied-piper:before {
|
||||
.fa-pied-piper-pp:before {
|
||||
content: "\f1a7";
|
||||
}
|
||||
.fa-pied-piper-alt:before {
|
||||
|
@ -1372,6 +1372,7 @@
|
|||
content: "\f1ce";
|
||||
}
|
||||
.fa-ra:before,
|
||||
.fa-resistance:before,
|
||||
.fa-rebel:before {
|
||||
content: "\f1d0";
|
||||
}
|
||||
|
@ -1694,6 +1695,7 @@
|
|||
content: "\f23e";
|
||||
}
|
||||
.fa-battery-4:before,
|
||||
.fa-battery:before,
|
||||
.fa-battery-full:before {
|
||||
content: "\f240";
|
||||
}
|
||||
|
@ -2020,6 +2022,163 @@
|
|||
.fa-snapchat-square:before {
|
||||
content: "\f2ad";
|
||||
}
|
||||
.fa-pied-piper:before {
|
||||
content: "\f2ae";
|
||||
}
|
||||
.fa-first-order:before {
|
||||
content: "\f2b0";
|
||||
}
|
||||
.fa-yoast:before {
|
||||
content: "\f2b1";
|
||||
}
|
||||
.fa-themeisle:before {
|
||||
content: "\f2b2";
|
||||
}
|
||||
.fa-google-plus-circle:before,
|
||||
.fa-google-plus-official:before {
|
||||
content: "\f2b3";
|
||||
}
|
||||
.fa-fa:before,
|
||||
.fa-font-awesome:before {
|
||||
content: "\f2b4";
|
||||
}
|
||||
.fa-handshake-o:before {
|
||||
content: "\f2b5";
|
||||
}
|
||||
.fa-envelope-open:before {
|
||||
content: "\f2b6";
|
||||
}
|
||||
.fa-envelope-open-o:before {
|
||||
content: "\f2b7";
|
||||
}
|
||||
.fa-linode:before {
|
||||
content: "\f2b8";
|
||||
}
|
||||
.fa-address-book:before {
|
||||
content: "\f2b9";
|
||||
}
|
||||
.fa-address-book-o:before {
|
||||
content: "\f2ba";
|
||||
}
|
||||
.fa-vcard:before,
|
||||
.fa-address-card:before {
|
||||
content: "\f2bb";
|
||||
}
|
||||
.fa-vcard-o:before,
|
||||
.fa-address-card-o:before {
|
||||
content: "\f2bc";
|
||||
}
|
||||
.fa-user-circle:before {
|
||||
content: "\f2bd";
|
||||
}
|
||||
.fa-user-circle-o:before {
|
||||
content: "\f2be";
|
||||
}
|
||||
.fa-user-o:before {
|
||||
content: "\f2c0";
|
||||
}
|
||||
.fa-id-badge:before {
|
||||
content: "\f2c1";
|
||||
}
|
||||
.fa-drivers-license:before,
|
||||
.fa-id-card:before {
|
||||
content: "\f2c2";
|
||||
}
|
||||
.fa-drivers-license-o:before,
|
||||
.fa-id-card-o:before {
|
||||
content: "\f2c3";
|
||||
}
|
||||
.fa-quora:before {
|
||||
content: "\f2c4";
|
||||
}
|
||||
.fa-free-code-camp:before {
|
||||
content: "\f2c5";
|
||||
}
|
||||
.fa-telegram:before {
|
||||
content: "\f2c6";
|
||||
}
|
||||
.fa-thermometer-4:before,
|
||||
.fa-thermometer:before,
|
||||
.fa-thermometer-full:before {
|
||||
content: "\f2c7";
|
||||
}
|
||||
.fa-thermometer-3:before,
|
||||
.fa-thermometer-three-quarters:before {
|
||||
content: "\f2c8";
|
||||
}
|
||||
.fa-thermometer-2:before,
|
||||
.fa-thermometer-half:before {
|
||||
content: "\f2c9";
|
||||
}
|
||||
.fa-thermometer-1:before,
|
||||
.fa-thermometer-quarter:before {
|
||||
content: "\f2ca";
|
||||
}
|
||||
.fa-thermometer-0:before,
|
||||
.fa-thermometer-empty:before {
|
||||
content: "\f2cb";
|
||||
}
|
||||
.fa-shower:before {
|
||||
content: "\f2cc";
|
||||
}
|
||||
.fa-bathtub:before,
|
||||
.fa-s15:before,
|
||||
.fa-bath:before {
|
||||
content: "\f2cd";
|
||||
}
|
||||
.fa-podcast:before {
|
||||
content: "\f2ce";
|
||||
}
|
||||
.fa-window-maximize:before {
|
||||
content: "\f2d0";
|
||||
}
|
||||
.fa-window-minimize:before {
|
||||
content: "\f2d1";
|
||||
}
|
||||
.fa-window-restore:before {
|
||||
content: "\f2d2";
|
||||
}
|
||||
.fa-times-rectangle:before,
|
||||
.fa-window-close:before {
|
||||
content: "\f2d3";
|
||||
}
|
||||
.fa-times-rectangle-o:before,
|
||||
.fa-window-close-o:before {
|
||||
content: "\f2d4";
|
||||
}
|
||||
.fa-bandcamp:before {
|
||||
content: "\f2d5";
|
||||
}
|
||||
.fa-grav:before {
|
||||
content: "\f2d6";
|
||||
}
|
||||
.fa-etsy:before {
|
||||
content: "\f2d7";
|
||||
}
|
||||
.fa-imdb:before {
|
||||
content: "\f2d8";
|
||||
}
|
||||
.fa-ravelry:before {
|
||||
content: "\f2d9";
|
||||
}
|
||||
.fa-eercast:before {
|
||||
content: "\f2da";
|
||||
}
|
||||
.fa-microchip:before {
|
||||
content: "\f2db";
|
||||
}
|
||||
.fa-snowflake-o:before {
|
||||
content: "\f2dc";
|
||||
}
|
||||
.fa-superpowers:before {
|
||||
content: "\f2dd";
|
||||
}
|
||||
.fa-wpexplorer:before {
|
||||
content: "\f2de";
|
||||
}
|
||||
.fa-meetup:before {
|
||||
content: "\f2e0";
|
||||
}
|
||||
.sr-only {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
|
|
|
@ -66,7 +66,7 @@
|
|||
|
||||
.phui-calendar-list-item-empty {
|
||||
color: {$lightgreytext};
|
||||
padding: 0 12px;
|
||||
padding: 0;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,26 +19,33 @@
|
|||
display: table-cell;
|
||||
position: relative;
|
||||
vertical-align: top;
|
||||
width: {$menu.profile.width};
|
||||
max-width: {$menu.profile.width};
|
||||
margin-top: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.phui-basic-nav.phui-navigation-shell .phabricator-nav-local {
|
||||
width: 205px;
|
||||
padding-top: 4px;
|
||||
padding-right: 8px;
|
||||
.phabricator-home.device-phone .phabricator-nav-content {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.phui-basic-nav .phabricator-side-menu {
|
||||
background-color: {$page.sidenav};
|
||||
.phabricator-home .phui-basic-nav .phabricator-side-menu {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.device-phone.phabricator-home .phui-basic-nav .phabricator-side-menu
|
||||
.phui-list-item-selected {
|
||||
background-color: transparent;
|
||||
border-left-color: transparent;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.phui-basic-nav.phui-navigation-shell .phabricator-nav-local {
|
||||
width: 205px;
|
||||
padding-top: 12px;
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
.phui-two-column-view .phui-basic-nav.phui-navigation-shell
|
||||
.phabricator-nav-local {
|
||||
width: {$menu.profile.width};
|
||||
max-width: {$menu.profile.width};
|
||||
padding-right: 0;
|
||||
padding-top: 0;
|
||||
}
|
||||
|
@ -55,13 +62,12 @@
|
|||
display: block;
|
||||
white-space: nowrap;
|
||||
text-decoration: none;
|
||||
font-size: 13px;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
.phui-basic-nav .phabricator-side-menu .phui-list-item-href {
|
||||
display: block;
|
||||
padding: 6px 8px 6px 24px;
|
||||
padding: 6px 8px 6px 20px;
|
||||
color: {$darkbluetext};
|
||||
border-top-right-radius: 3px;
|
||||
border-bottom-right-radius: 3px;
|
||||
|
@ -69,10 +75,30 @@
|
|||
text-overflow: ellipsis
|
||||
}
|
||||
|
||||
.phui-basic-nav .phabricator-side-menu .phui-list-item-has-icon
|
||||
.phui-list-item-href {
|
||||
padding-left: 12px;
|
||||
}
|
||||
|
||||
.phui-basic-nav .phabricator-side-menu .phui-list-item-icon {
|
||||
margin-left: -12px;
|
||||
margin-left: -4px;
|
||||
text-align: center;
|
||||
width: 24px;
|
||||
width: 30px;
|
||||
}
|
||||
|
||||
.phui-basic-nav .phabricator-side-menu .phui-divider {
|
||||
border-bottom: 1px solid rgba({$alphablack},.08);
|
||||
margin: 0 0 8px 8px;
|
||||
padding: 8px 0 0 0;
|
||||
}
|
||||
|
||||
.phui-basic-nav .phabricator-side-menu .phui-list-item-icon.phuihead-small {
|
||||
display: inline-block;
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
border-radius: 3px;
|
||||
background-size: 100%;
|
||||
margin: -2px 7px -2px 3px;
|
||||
}
|
||||
|
||||
.phui-basic-nav .phabricator-side-menu .phui-list-item-selected {
|
||||
|
@ -91,7 +117,7 @@
|
|||
|
||||
.phui-basic-nav .phabricator-side-menu .phui-list-item-selected
|
||||
.phui-list-item-href {
|
||||
padding-left: 20px;
|
||||
margin-left: -4px;
|
||||
}
|
||||
|
||||
.phui-basic-nav .phabricator-side-menu .phui-list-item-type-label {
|
||||
|
@ -108,3 +134,12 @@
|
|||
text-decoration: none;
|
||||
background-color: rgba({$alphablack},.07);
|
||||
}
|
||||
|
||||
.phui-basic-nav .phabricator-side-menu .phui-list-item-type-link +
|
||||
.phui-list-item-type-label {
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.phui-basic-nav .phui-profile-segment-bar {
|
||||
padding: 4px 4px 8px 12px;
|
||||
}
|
||||
|
|
|
@ -49,10 +49,11 @@
|
|||
|
||||
.phui-object-box.phui-box-blue div.phui-info-severity-nodata,
|
||||
.phui-object-box.phui-box-grey div.phui-info-severity-nodata {
|
||||
background: transparent;
|
||||
padding: 20px 4px 24px;
|
||||
background: #fff;
|
||||
padding: 32px 0;
|
||||
text-align: center;
|
||||
border: none;
|
||||
margin: 0;
|
||||
color: {$greytext};
|
||||
}
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue