2011-01-16 22:51:39 +01:00
|
|
|
<?php
|
|
|
|
|
2012-10-16 19:33:47 +02:00
|
|
|
/**
|
|
|
|
* This is a standard Phabricator page with menus, Javelin, DarkConsole, and
|
|
|
|
* basic styles.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
final class PhabricatorStandardPageView extends PhabricatorBarePageView {
|
2011-01-16 22:51:39 +01:00
|
|
|
|
|
|
|
private $baseURI;
|
|
|
|
private $applicationName;
|
|
|
|
private $glyph;
|
2012-07-31 15:18:38 +02:00
|
|
|
private $menuContent;
|
Countdown tweaks
Summary:
A few tweaks to hsb's Countdown implementation:
- Allow the page to be rendered "chromeless", suitable for display on one of
the dozens of monitors everyone has laying around.
- Show title of countdown in deletion dialog.
- When creating a new countdown default to time(), not Dec 31, 1969.
- Add extra "/" after editing to avoid needless redirect.
- Tweak some page titles.
- Show countdown author in list view.
- Highlight tab in list view.
- Tweak menu copy.
- Link countdown title in list view, separate buttons into different columns
so they pick up padding.
Test Plan:
Created, edited and deleted a timer. Viewed a timer and toggled chrome mode.
Viewed timer list.
Reviewed By: hsb
Reviewers: hsb, aran, jungejason, tuomaspelkonen
CC: aran, hsb, epriestley
Differential Revision: 454
2011-06-14 02:35:13 +02:00
|
|
|
private $showChrome = true;
|
2011-07-09 18:45:19 +02:00
|
|
|
private $disableConsole;
|
2012-06-14 02:28:21 +02:00
|
|
|
private $pageObjects = array();
|
2012-12-07 22:34:44 +01:00
|
|
|
private $applicationMenu;
|
2014-09-10 23:44:34 +02:00
|
|
|
private $showFooter = true;
|
2015-01-27 15:30:52 +01:00
|
|
|
private $showDurableColumn = true;
|
2014-09-10 23:44:34 +02:00
|
|
|
|
|
|
|
public function setShowFooter($show_footer) {
|
|
|
|
$this->showFooter = $show_footer;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getShowFooter() {
|
|
|
|
return $this->showFooter;
|
|
|
|
}
|
2012-12-07 22:34:44 +01:00
|
|
|
|
2013-06-05 17:41:43 +02:00
|
|
|
public function setApplicationMenu(PHUIListView $application_menu) {
|
2012-12-07 22:34:44 +01:00
|
|
|
$this->applicationMenu = $application_menu;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getApplicationMenu() {
|
|
|
|
return $this->applicationMenu;
|
|
|
|
}
|
2011-01-16 22:51:39 +01:00
|
|
|
|
|
|
|
public function setApplicationName($application_name) {
|
|
|
|
$this->applicationName = $application_name;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2011-07-09 18:45:19 +02:00
|
|
|
public function setDisableConsole($disable) {
|
|
|
|
$this->disableConsole = $disable;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2011-01-16 22:51:39 +01:00
|
|
|
public function getApplicationName() {
|
|
|
|
return $this->applicationName;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function setBaseURI($base_uri) {
|
|
|
|
$this->baseURI = $base_uri;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getBaseURI() {
|
|
|
|
return $this->baseURI;
|
|
|
|
}
|
|
|
|
|
Countdown tweaks
Summary:
A few tweaks to hsb's Countdown implementation:
- Allow the page to be rendered "chromeless", suitable for display on one of
the dozens of monitors everyone has laying around.
- Show title of countdown in deletion dialog.
- When creating a new countdown default to time(), not Dec 31, 1969.
- Add extra "/" after editing to avoid needless redirect.
- Tweak some page titles.
- Show countdown author in list view.
- Highlight tab in list view.
- Tweak menu copy.
- Link countdown title in list view, separate buttons into different columns
so they pick up padding.
Test Plan:
Created, edited and deleted a timer. Viewed a timer and toggled chrome mode.
Viewed timer list.
Reviewed By: hsb
Reviewers: hsb, aran, jungejason, tuomaspelkonen
CC: aran, hsb, epriestley
Differential Revision: 454
2011-06-14 02:35:13 +02:00
|
|
|
public function setShowChrome($show_chrome) {
|
|
|
|
$this->showChrome = $show_chrome;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getShowChrome() {
|
|
|
|
return $this->showChrome;
|
|
|
|
}
|
|
|
|
|
2012-06-14 02:28:21 +02:00
|
|
|
public function appendPageObjects(array $objs) {
|
|
|
|
foreach ($objs as $obj) {
|
|
|
|
$this->pageObjects[] = $obj;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-27 15:30:52 +01:00
|
|
|
public function setShowDurableColumn($show) {
|
|
|
|
$this->showDurableColumn = $show;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getShowDurableColumn() {
|
Conpherence - make the durable column kind of work and stuff
Summary:
Ref T7014. This hooks up the durable column such that when you open it up it loads your most recent Conpherence. You can then switch amongst the various widgets and stuff and everything works nicely.
Except...
- scroll bar does not work
- also doesn't work at HEAD when I add a ton of text to the UI with no changes? (wrapped $copy in array_fill(0, 1000, $copy))
- "widget selector" does not collapse when you select something else
- this part wasn't really specified so I used the aphlict dropdown stuff. didn't want to keep working on that if this was the wrong UI choice
- can not edit title
- do we still want that to be done by clicking on the title, which pops a dialogue?
- can not add participants or calendar events
- what should this UI be? maybe just a button on the top for "participants" and a button on the bottom for calendar? both on top?
- this is not pixel perfect to the mock or two I've seen around. Aside from generally being bad at that, I definitely didn't get the name + timestamps formatting correctly, because the standard DOM of that has timestamp FIRST which appears second due to a "float right". Seemed like a lot of special-casing for what might not even be that important in the UI so I punted. (And again, there's likely many unknown ways in which this isn't pixel perfect)
There's also code quality issues
- `ConpherenceWidgetConfigConstants` is hopefully temporary or at least gets more sleek as we keep progressing here
- copied some CSS from main Conpherence app
- DOM structure is pretty different
- there's some minor CSS tweaks too given the different width (not to mention the DOM structure being different)
- copied some JS from behavior-pontificate.js to sync threads relative to aphlict updates
- JS in general is like a better version of existing JS; these should collapse I'd hope?
- maybe the aphlict-behavior-dropdown change was badsauce?
...but all that said, this definitely feels really nice and I feel like adding stuff is going to be really easy compared to how normal Conpherence is.
Also includes a bonus bug fix - we now correctly update participation. The user would encounter this issue if they were in a conpherence that got some updates and then they went to a different page; they would have unread status for the messages that were ajax'd in. This patch fixes that by making sure we mark participation up to date with the proper transaction in all cases.
Test Plan: hit "\" to invoke the column and saw nice loading UI and my latest conpherence load. sent messages and verified they received A-OK by looking in DOM console. toggled various widges and verified they rendered correctly. opened up a second browser with a second user on the thread, sent a message, and it was received in a nice asynchronous fashion
Reviewers: chad, epriestley
Reviewed By: epriestley
Subscribers: Korvin, epriestley
Maniphest Tasks: T7014
Differential Revision: https://secure.phabricator.com/D11968
2015-03-05 19:33:39 +01:00
|
|
|
$request = $this->getRequest();
|
2015-03-10 23:32:15 +01:00
|
|
|
if (!$request) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
$viewer = $request->getUser();
|
|
|
|
if (!$viewer->isLoggedIn()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
$conpherence_installed = PhabricatorApplication::isClassInstalledForViewer(
|
|
|
|
'PhabricatorConpherenceApplication',
|
|
|
|
$viewer);
|
|
|
|
if (!$conpherence_installed) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
$patterns = $this->getQuicksandURIPatternBlacklist();
|
|
|
|
$path = $request->getRequestURI()->getPath();
|
|
|
|
foreach ($patterns as $pattern) {
|
|
|
|
if (preg_match('(^'.$pattern.'$)', $path)) {
|
2015-03-10 20:20:29 +01:00
|
|
|
return false;
|
|
|
|
}
|
Conpherence - make the durable column kind of work and stuff
Summary:
Ref T7014. This hooks up the durable column such that when you open it up it loads your most recent Conpherence. You can then switch amongst the various widgets and stuff and everything works nicely.
Except...
- scroll bar does not work
- also doesn't work at HEAD when I add a ton of text to the UI with no changes? (wrapped $copy in array_fill(0, 1000, $copy))
- "widget selector" does not collapse when you select something else
- this part wasn't really specified so I used the aphlict dropdown stuff. didn't want to keep working on that if this was the wrong UI choice
- can not edit title
- do we still want that to be done by clicking on the title, which pops a dialogue?
- can not add participants or calendar events
- what should this UI be? maybe just a button on the top for "participants" and a button on the bottom for calendar? both on top?
- this is not pixel perfect to the mock or two I've seen around. Aside from generally being bad at that, I definitely didn't get the name + timestamps formatting correctly, because the standard DOM of that has timestamp FIRST which appears second due to a "float right". Seemed like a lot of special-casing for what might not even be that important in the UI so I punted. (And again, there's likely many unknown ways in which this isn't pixel perfect)
There's also code quality issues
- `ConpherenceWidgetConfigConstants` is hopefully temporary or at least gets more sleek as we keep progressing here
- copied some CSS from main Conpherence app
- DOM structure is pretty different
- there's some minor CSS tweaks too given the different width (not to mention the DOM structure being different)
- copied some JS from behavior-pontificate.js to sync threads relative to aphlict updates
- JS in general is like a better version of existing JS; these should collapse I'd hope?
- maybe the aphlict-behavior-dropdown change was badsauce?
...but all that said, this definitely feels really nice and I feel like adding stuff is going to be really easy compared to how normal Conpherence is.
Also includes a bonus bug fix - we now correctly update participation. The user would encounter this issue if they were in a conpherence that got some updates and then they went to a different page; they would have unread status for the messages that were ajax'd in. This patch fixes that by making sure we mark participation up to date with the proper transaction in all cases.
Test Plan: hit "\" to invoke the column and saw nice loading UI and my latest conpherence load. sent messages and verified they received A-OK by looking in DOM console. toggled various widges and verified they rendered correctly. opened up a second browser with a second user on the thread, sent a message, and it was received in a nice asynchronous fashion
Reviewers: chad, epriestley
Reviewed By: epriestley
Subscribers: Korvin, epriestley
Maniphest Tasks: T7014
Differential Revision: https://secure.phabricator.com/D11968
2015-03-05 19:33:39 +01:00
|
|
|
}
|
2015-03-10 23:32:15 +01:00
|
|
|
|
|
|
|
return true;
|
2015-01-27 15:30:52 +01:00
|
|
|
}
|
|
|
|
|
2015-03-11 02:46:16 +01:00
|
|
|
public function getDurableColumnVisible() {
|
|
|
|
$column_key = PhabricatorUserPreferences::PREFERENCE_CONPHERENCE_COLUMN;
|
|
|
|
return (bool)$this->getUserPreference($column_key, 0);
|
|
|
|
}
|
2013-05-15 17:38:56 +02:00
|
|
|
|
2015-03-11 02:46:16 +01:00
|
|
|
|
|
|
|
public function getTitle() {
|
|
|
|
$glyph_key = PhabricatorUserPreferences::PREFERENCE_TITLES;
|
|
|
|
if ($this->getUserPreference($glyph_key) == 'text') {
|
|
|
|
$use_glyph = false;
|
|
|
|
} else {
|
|
|
|
$use_glyph = true;
|
2011-03-31 04:21:09 +02:00
|
|
|
}
|
|
|
|
|
2013-05-15 17:38:56 +02:00
|
|
|
$title = parent::getTitle();
|
|
|
|
|
|
|
|
$prefix = null;
|
|
|
|
if ($use_glyph) {
|
|
|
|
$prefix = $this->getGlyph();
|
|
|
|
} else {
|
|
|
|
$application_name = $this->getApplicationName();
|
|
|
|
if (strlen($application_name)) {
|
|
|
|
$prefix = '['.$application_name.']';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (strlen($prefix)) {
|
|
|
|
$title = $prefix.' '.$title;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $title;
|
2011-01-16 22:51:39 +01:00
|
|
|
}
|
|
|
|
|
2011-01-25 20:31:40 +01:00
|
|
|
|
2011-01-25 18:59:31 +01:00
|
|
|
protected function willRenderPage() {
|
2012-10-16 19:33:47 +02:00
|
|
|
parent::willRenderPage();
|
2011-02-02 22:48:52 +01:00
|
|
|
|
|
|
|
if (!$this->getRequest()) {
|
|
|
|
throw new Exception(
|
2013-03-02 00:37:32 +01:00
|
|
|
pht(
|
2014-06-09 20:36:49 +02:00
|
|
|
'You must set the Request to render a PhabricatorStandardPageView.'));
|
2011-02-02 22:48:52 +01:00
|
|
|
}
|
|
|
|
|
2011-07-09 18:45:19 +02:00
|
|
|
$console = $this->getConsole();
|
2011-02-02 22:48:52 +01:00
|
|
|
|
2011-01-25 18:59:31 +01:00
|
|
|
require_celerity_resource('phabricator-core-css');
|
2012-12-30 18:30:21 +01:00
|
|
|
require_celerity_resource('phabricator-zindex-css');
|
2013-06-13 03:23:35 +02:00
|
|
|
require_celerity_resource('phui-button-css');
|
|
|
|
require_celerity_resource('phui-spacing-css');
|
|
|
|
require_celerity_resource('phui-form-css');
|
2012-12-07 22:35:49 +01:00
|
|
|
require_celerity_resource('sprite-gradient-css');
|
2011-01-25 20:31:40 +01:00
|
|
|
require_celerity_resource('phabricator-standard-page-view');
|
2015-03-12 00:20:13 +01:00
|
|
|
require_celerity_resource('conpherence-durable-column-view');
|
2011-01-25 20:31:40 +01:00
|
|
|
|
2012-11-20 02:05:10 +01:00
|
|
|
Javelin::initBehavior('workflow', array());
|
|
|
|
|
Prevent CSRF uploads via /file/dropupload/
Summary:
We don't currently validate CSRF tokens on this workflow. This allows an
attacker to upload arbitrary files on the user's behalf. Although I believe the
tight list of servable mime-types means that's more or less the end of the
attack, this is still a vulnerability.
In the long term, the right solution is probably to pass CSRF tokens on all Ajax
requests in an HTTP header (or just a GET param) or something like that.
However, this endpoint is unique and this is the quickest and most direct way to
close the hole.
Test Plan:
- Drop-uploaded files to Files, Maniphest, Phriction and Differential.
- Modified CSRF vaidator to use __csrf__.'x' and verified uploads and form
submissions don't work.
Reviewers: andrewjcg, aran, jungejason, tuomaspelkonen, erling
Commenters: andrewjcg, pedram
CC: aran, epriestley, andrewjcg, pedram
Differential Revision: 758
2011-08-02 05:23:01 +02:00
|
|
|
$request = $this->getRequest();
|
2013-01-29 03:12:09 +01:00
|
|
|
$user = null;
|
Prevent CSRF uploads via /file/dropupload/
Summary:
We don't currently validate CSRF tokens on this workflow. This allows an
attacker to upload arbitrary files on the user's behalf. Although I believe the
tight list of servable mime-types means that's more or less the end of the
attack, this is still a vulnerability.
In the long term, the right solution is probably to pass CSRF tokens on all Ajax
requests in an HTTP header (or just a GET param) or something like that.
However, this endpoint is unique and this is the quickest and most direct way to
close the hole.
Test Plan:
- Drop-uploaded files to Files, Maniphest, Phriction and Differential.
- Modified CSRF vaidator to use __csrf__.'x' and verified uploads and form
submissions don't work.
Reviewers: andrewjcg, aran, jungejason, tuomaspelkonen, erling
Commenters: andrewjcg, pedram
CC: aran, epriestley, andrewjcg, pedram
Differential Revision: 758
2011-08-02 05:23:01 +02:00
|
|
|
if ($request) {
|
|
|
|
$user = $request->getUser();
|
|
|
|
}
|
|
|
|
|
2013-01-29 03:12:09 +01:00
|
|
|
if ($user) {
|
|
|
|
$default_img_uri =
|
2014-07-25 00:19:52 +02:00
|
|
|
celerity_get_resource_uri(
|
|
|
|
'rsrc/image/icon/fatcow/document_black.png');
|
2013-01-30 20:30:38 +01:00
|
|
|
$download_form = phabricator_form(
|
2013-01-29 03:12:09 +01:00
|
|
|
$user,
|
|
|
|
array(
|
|
|
|
'action' => '#',
|
|
|
|
'method' => 'POST',
|
|
|
|
'class' => 'lightbox-download-form',
|
|
|
|
'sigil' => 'download',
|
|
|
|
),
|
|
|
|
phutil_tag(
|
|
|
|
'button',
|
|
|
|
array(),
|
|
|
|
pht('Download')));
|
|
|
|
|
|
|
|
Javelin::initBehavior(
|
|
|
|
'lightbox-attachments',
|
|
|
|
array(
|
|
|
|
'defaultImageUri' => $default_img_uri,
|
|
|
|
'downloadForm' => $download_form,
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
|
|
|
Javelin::initBehavior('aphront-form-disable-on-submit');
|
2012-07-31 01:08:42 +02:00
|
|
|
Javelin::initBehavior('toggle-class', array());
|
2013-03-01 03:58:00 +01:00
|
|
|
Javelin::initBehavior('history-install');
|
Add support for device swipe events
Summary:
Ref T2700. Allow JS to listen for swipes on devices.
There are a bunch of tricky cases here and I probably didn't get them all totally right, but this interaction broadly looks like this:
- We implement gesture recognition for the mouse in device modes (narrow browser), and for touch events from an actual device.
- The sigil `touchable` indicates that a node wants to react to touch events.
- When the user touches a `touchable` node, we start listening for moves. They might be tapping/clicking (in which case we don't care), but they might also be gesturing.
- Once the user moves their finger/pointer far enough away from the tap origin, we recognize it as a gesture. I hardcoded this at 20px; I wasn't able to find any "official" Apple value, but 20px seems like a common default.
- At this point, we look at where their finger has moved.
- If they moved it mostly up/down, we interpret the gesture as "scroll" and just stop listening. The device does its own thing.
- However, if they moved it mostly left/right, we interpret it as a "swipe". We start killing the moves so the device doesn't scroll.
- Once we've recognized that a gesture is underway, we send a "gesture.swipe.start" event and then "gesture.swipe.move" events for every move.
- When the user ends the gesture, we send "gesture.swipe.end".
- If the user cancels the gesture (currently, only by tapping with a second finger), we send "gesture.swipe.cancel".
- Gesture events have raw position data and some convenience fields.
Test Plan:
Wrote UI example and used it from the Desktop, iPhone simulator, and a real iphone.
- The code always seems to get "scroll" vs "swipe" correct (i.e., consistent with my intentions).
- The threshold feels pretty good to me.
- Tapping with a second finger cancels the action.
Reviewers: chad, btrahan
Reviewed By: chad
CC: aran
Maniphest Tasks: T2700
Differential Revision: https://secure.phabricator.com/D5308
2013-03-09 22:53:15 +01:00
|
|
|
Javelin::initBehavior('phabricator-gesture');
|
2013-01-29 03:12:09 +01:00
|
|
|
|
|
|
|
$current_token = null;
|
|
|
|
if ($user) {
|
|
|
|
$current_token = $user->getCSRFToken();
|
|
|
|
}
|
|
|
|
|
Prevent CSRF uploads via /file/dropupload/
Summary:
We don't currently validate CSRF tokens on this workflow. This allows an
attacker to upload arbitrary files on the user's behalf. Although I believe the
tight list of servable mime-types means that's more or less the end of the
attack, this is still a vulnerability.
In the long term, the right solution is probably to pass CSRF tokens on all Ajax
requests in an HTTP header (or just a GET param) or something like that.
However, this endpoint is unique and this is the quickest and most direct way to
close the hole.
Test Plan:
- Drop-uploaded files to Files, Maniphest, Phriction and Differential.
- Modified CSRF vaidator to use __csrf__.'x' and verified uploads and form
submissions don't work.
Reviewers: andrewjcg, aran, jungejason, tuomaspelkonen, erling
Commenters: andrewjcg, pedram
CC: aran, epriestley, andrewjcg, pedram
Differential Revision: 758
2011-08-02 05:23:01 +02:00
|
|
|
Javelin::initBehavior(
|
|
|
|
'refresh-csrf',
|
|
|
|
array(
|
|
|
|
'tokenName' => AphrontRequest::getCSRFTokenName(),
|
|
|
|
'header' => AphrontRequest::getCSRFHeaderName(),
|
|
|
|
'current' => $current_token,
|
|
|
|
));
|
2013-01-29 03:12:09 +01:00
|
|
|
|
2012-12-11 23:01:51 +01:00
|
|
|
Javelin::initBehavior('device');
|
2012-03-15 04:47:17 +01:00
|
|
|
|
2014-04-28 02:31:11 +02:00
|
|
|
if ($user->hasSession()) {
|
|
|
|
$hisec = ($user->getSession()->getHighSecurityUntil() - time());
|
|
|
|
if ($hisec > 0) {
|
2014-07-13 04:03:17 +02:00
|
|
|
$remaining_time = phutil_format_relative_time($hisec);
|
2014-04-28 02:31:11 +02:00
|
|
|
Javelin::initBehavior(
|
|
|
|
'high-security-warning',
|
|
|
|
array(
|
|
|
|
'uri' => '/auth/session/downgrade/',
|
|
|
|
'message' => pht(
|
|
|
|
'Your session is in high security mode. When you '.
|
|
|
|
'finish using it, click here to leave.',
|
|
|
|
$remaining_time),
|
|
|
|
));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-02 22:48:52 +01:00
|
|
|
if ($console) {
|
|
|
|
require_celerity_resource('aphront-dark-console-css');
|
2013-02-09 22:29:47 +01:00
|
|
|
|
|
|
|
$headers = array();
|
2013-02-10 00:47:55 +01:00
|
|
|
if (DarkConsoleXHProfPluginAPI::isProfilerStarted()) {
|
2013-02-09 22:29:47 +01:00
|
|
|
$headers[DarkConsoleXHProfPluginAPI::getProfilerHeader()] = 'page';
|
|
|
|
}
|
2013-11-19 23:10:45 +01:00
|
|
|
if (DarkConsoleServicesPlugin::isQueryAnalyzerRequested()) {
|
|
|
|
$headers[DarkConsoleServicesPlugin::getQueryAnalyzerHeader()] = true;
|
|
|
|
}
|
2013-02-09 22:29:47 +01:00
|
|
|
|
2011-02-02 22:48:52 +01:00
|
|
|
Javelin::initBehavior(
|
|
|
|
'dark-console',
|
|
|
|
array(
|
2013-08-08 01:09:25 +02:00
|
|
|
// NOTE: We use a generic label here to prevent input reflection
|
|
|
|
// and mitigate compression attacks like BREACH. See discussion in
|
|
|
|
// T3684.
|
|
|
|
'uri' => pht('Main Request'),
|
DarkConsole: fix rendering, move request log, load over ajax
Summary:
This accomplishes three major goals:
# Fixes phutil_render_tag -> phutil_tag callsites in DarkConsole.
# Moves the Ajax request log to a new panel on the left. This panel (and the tabs panel) get scrollbars when they get large, instead of making the page constantly scroll down.
# Loads the panel content over ajax, instead of dumping it into the page body / ajax response body. I've been planning to do this for about 3 years, which is why the plugins are architected the way they are. This should make debugging easier by making response bodies not be 50%+ darkconsole stuff.
Additionally, load the plugins dynamically (the old method predates library maps and PhutilSymbolLoader).
Test Plan:
{F30675}
- Switched between requests and tabs, reloaded page, saw same tab.
- Used "analyze queries", "profile page", triggered errors.
- Verified page does not load anything by default if dark console is closed with Charles.
- Generally banged on it a bit.
Reviewers: vrana, btrahan, chad
Reviewed By: vrana
CC: aran
Maniphest Tasks: T2432
Differential Revision: https://secure.phabricator.com/D4692
2013-01-29 03:45:32 +01:00
|
|
|
'selected' => $user ? $user->getConsoleTab() : null,
|
|
|
|
'visible' => $user ? (int)$user->getConsoleVisible() : true,
|
2013-02-09 22:29:47 +01:00
|
|
|
'headers' => $headers,
|
2011-02-02 22:48:52 +01:00
|
|
|
));
|
2011-04-05 21:24:21 +02:00
|
|
|
|
|
|
|
// Change this to initBehavior when there is some behavior to initialize
|
|
|
|
require_celerity_resource('javelin-behavior-error-log');
|
2011-02-02 22:48:52 +01:00
|
|
|
}
|
|
|
|
|
2013-10-13 02:08:47 +02:00
|
|
|
if ($user) {
|
|
|
|
$viewer = $user;
|
|
|
|
} else {
|
|
|
|
$viewer = new PhabricatorUser();
|
|
|
|
}
|
|
|
|
|
2012-12-07 22:34:44 +01:00
|
|
|
$menu = id(new PhabricatorMainMenuView())
|
Replace "search scope" with selectable default behavior
Summary:
Fixes T4365. See discussion in D8123.
This implements the most conservative solution of approaches discussed in D8123. Basically:
- When you search in primary search, we overwrite "query" in your default (topmost) search filter, and execute that.
This doesn't implement any of the other "sticky" stuff, where the query sticks around. Maybe we'll do that eventually, but it gets messy and could be confusing. Practically, this addresses the major use case in the wild, which is to make the menu bar search mean "Open Tasks" by default.
This also removes the old, obsolete "search scope" stuff. A long time ago, searching from within Maniphest would search tasks, etc., but this was pretty weird and confusing and is no longer used, and no one complained when we got rid of it.
Test Plan: Dragged "Open Tasks" to my top search, searched for "asdf", got "asdf in open tasks" results.
Reviewers: btrahan, chad
Reviewed By: btrahan
CC: bigo, aran
Maniphest Tasks: T4365
Differential Revision: https://secure.phabricator.com/D8135
2014-02-03 23:29:49 +01:00
|
|
|
->setUser($viewer);
|
2012-12-07 22:34:44 +01:00
|
|
|
|
2012-12-08 00:29:41 +01:00
|
|
|
if ($this->getController()) {
|
|
|
|
$menu->setController($this->getController());
|
|
|
|
}
|
|
|
|
|
2012-12-07 22:34:44 +01:00
|
|
|
if ($this->getApplicationMenu()) {
|
|
|
|
$menu->setApplicationMenu($this->getApplicationMenu());
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->menuContent = $menu->render();
|
2011-01-25 18:59:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-01-16 22:51:39 +01:00
|
|
|
protected function getHead() {
|
2015-04-06 17:08:53 +02:00
|
|
|
$monospaced = null;
|
2011-03-31 04:21:09 +02:00
|
|
|
|
|
|
|
$request = $this->getRequest();
|
|
|
|
if ($request) {
|
|
|
|
$user = $request->getUser();
|
|
|
|
if ($user) {
|
2015-04-06 17:08:53 +02:00
|
|
|
$monospaced = $user->loadPreferences()->getPreference(
|
2013-04-01 22:48:57 +02:00
|
|
|
PhabricatorUserPreferences::PREFERENCE_MONOSPACED);
|
2011-03-31 04:21:09 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-16 19:33:47 +02:00
|
|
|
$response = CelerityAPI::getStaticResourceResponse();
|
2012-07-25 20:51:27 +02:00
|
|
|
|
2015-02-28 23:37:31 +01:00
|
|
|
$font_css = null;
|
|
|
|
if (!empty($monospaced)) {
|
|
|
|
$font_css = hsprintf(
|
|
|
|
'<style type="text/css">'.
|
|
|
|
'.PhabricatorMonospaced, '.
|
|
|
|
'.phabricator-remarkup .remarkup-code-block '.
|
|
|
|
'.remarkup-code { font: %s !important; } '.
|
|
|
|
'</style>', $monospaced);
|
|
|
|
}
|
|
|
|
|
2013-02-13 23:50:15 +01:00
|
|
|
return hsprintf(
|
2015-04-06 17:08:53 +02:00
|
|
|
'%s%s%s',
|
2012-10-16 19:33:47 +02:00
|
|
|
parent::getHead(),
|
2015-02-28 23:37:31 +01:00
|
|
|
$font_css,
|
2014-01-01 16:46:18 +01:00
|
|
|
$response->renderSingleResource('javelin-magical-init', 'phabricator'));
|
2011-01-16 22:51:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
public function setGlyph($glyph) {
|
|
|
|
$this->glyph = $glyph;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getGlyph() {
|
|
|
|
return $this->glyph;
|
|
|
|
}
|
|
|
|
|
2011-02-02 22:48:52 +01:00
|
|
|
protected function willSendResponse($response) {
|
DarkConsole: fix rendering, move request log, load over ajax
Summary:
This accomplishes three major goals:
# Fixes phutil_render_tag -> phutil_tag callsites in DarkConsole.
# Moves the Ajax request log to a new panel on the left. This panel (and the tabs panel) get scrollbars when they get large, instead of making the page constantly scroll down.
# Loads the panel content over ajax, instead of dumping it into the page body / ajax response body. I've been planning to do this for about 3 years, which is why the plugins are architected the way they are. This should make debugging easier by making response bodies not be 50%+ darkconsole stuff.
Additionally, load the plugins dynamically (the old method predates library maps and PhutilSymbolLoader).
Test Plan:
{F30675}
- Switched between requests and tabs, reloaded page, saw same tab.
- Used "analyze queries", "profile page", triggered errors.
- Verified page does not load anything by default if dark console is closed with Charles.
- Generally banged on it a bit.
Reviewers: vrana, btrahan, chad
Reviewed By: vrana
CC: aran
Maniphest Tasks: T2432
Differential Revision: https://secure.phabricator.com/D4692
2013-01-29 03:45:32 +01:00
|
|
|
$request = $this->getRequest();
|
2012-10-16 19:33:47 +02:00
|
|
|
$response = parent::willSendResponse($response);
|
|
|
|
|
DarkConsole: fix rendering, move request log, load over ajax
Summary:
This accomplishes three major goals:
# Fixes phutil_render_tag -> phutil_tag callsites in DarkConsole.
# Moves the Ajax request log to a new panel on the left. This panel (and the tabs panel) get scrollbars when they get large, instead of making the page constantly scroll down.
# Loads the panel content over ajax, instead of dumping it into the page body / ajax response body. I've been planning to do this for about 3 years, which is why the plugins are architected the way they are. This should make debugging easier by making response bodies not be 50%+ darkconsole stuff.
Additionally, load the plugins dynamically (the old method predates library maps and PhutilSymbolLoader).
Test Plan:
{F30675}
- Switched between requests and tabs, reloaded page, saw same tab.
- Used "analyze queries", "profile page", triggered errors.
- Verified page does not load anything by default if dark console is closed with Charles.
- Generally banged on it a bit.
Reviewers: vrana, btrahan, chad
Reviewed By: vrana
CC: aran
Maniphest Tasks: T2432
Differential Revision: https://secure.phabricator.com/D4692
2013-01-29 03:45:32 +01:00
|
|
|
$console = $request->getApplicationConfiguration()->getConsole();
|
|
|
|
|
2011-02-02 22:48:52 +01:00
|
|
|
if ($console) {
|
2013-02-13 23:50:15 +01:00
|
|
|
$response = PhutilSafeHTML::applyFunction(
|
|
|
|
'str_replace',
|
|
|
|
hsprintf('<darkconsole />'),
|
DarkConsole: fix rendering, move request log, load over ajax
Summary:
This accomplishes three major goals:
# Fixes phutil_render_tag -> phutil_tag callsites in DarkConsole.
# Moves the Ajax request log to a new panel on the left. This panel (and the tabs panel) get scrollbars when they get large, instead of making the page constantly scroll down.
# Loads the panel content over ajax, instead of dumping it into the page body / ajax response body. I've been planning to do this for about 3 years, which is why the plugins are architected the way they are. This should make debugging easier by making response bodies not be 50%+ darkconsole stuff.
Additionally, load the plugins dynamically (the old method predates library maps and PhutilSymbolLoader).
Test Plan:
{F30675}
- Switched between requests and tabs, reloaded page, saw same tab.
- Used "analyze queries", "profile page", triggered errors.
- Verified page does not load anything by default if dark console is closed with Charles.
- Generally banged on it a bit.
Reviewers: vrana, btrahan, chad
Reviewed By: vrana
CC: aran
Maniphest Tasks: T2432
Differential Revision: https://secure.phabricator.com/D4692
2013-01-29 03:45:32 +01:00
|
|
|
$console->render($request),
|
2011-02-02 22:48:52 +01:00
|
|
|
$response);
|
|
|
|
}
|
2012-10-16 19:33:47 +02:00
|
|
|
|
2011-02-02 22:48:52 +01:00
|
|
|
return $response;
|
|
|
|
}
|
|
|
|
|
2011-01-16 22:51:39 +01:00
|
|
|
protected function getBody() {
|
2011-02-27 05:57:21 +01:00
|
|
|
$user = null;
|
2013-01-18 01:25:47 +01:00
|
|
|
$request = $this->getRequest();
|
2011-01-26 02:17:19 +01:00
|
|
|
if ($request) {
|
|
|
|
$user = $request->getUser();
|
2011-01-26 22:21:12 +01:00
|
|
|
}
|
2011-02-05 21:20:18 +01:00
|
|
|
|
Countdown tweaks
Summary:
A few tweaks to hsb's Countdown implementation:
- Allow the page to be rendered "chromeless", suitable for display on one of
the dozens of monitors everyone has laying around.
- Show title of countdown in deletion dialog.
- When creating a new countdown default to time(), not Dec 31, 1969.
- Add extra "/" after editing to avoid needless redirect.
- Tweak some page titles.
- Show countdown author in list view.
- Highlight tab in list view.
- Tweak menu copy.
- Link countdown title in list view, separate buttons into different columns
so they pick up padding.
Test Plan:
Created, edited and deleted a timer. Viewed a timer and toggled chrome mode.
Viewed timer list.
Reviewed By: hsb
Reviewers: hsb, aran, jungejason, tuomaspelkonen
CC: aran, hsb, epriestley
Differential Revision: 454
2011-06-14 02:35:13 +02:00
|
|
|
$header_chrome = null;
|
|
|
|
if ($this->getShowChrome()) {
|
2012-07-31 15:18:38 +02:00
|
|
|
$header_chrome = $this->menuContent;
|
Countdown tweaks
Summary:
A few tweaks to hsb's Countdown implementation:
- Allow the page to be rendered "chromeless", suitable for display on one of
the dozens of monitors everyone has laying around.
- Show title of countdown in deletion dialog.
- When creating a new countdown default to time(), not Dec 31, 1969.
- Add extra "/" after editing to avoid needless redirect.
- Tweak some page titles.
- Show countdown author in list view.
- Highlight tab in list view.
- Tweak menu copy.
- Link countdown title in list view, separate buttons into different columns
so they pick up padding.
Test Plan:
Created, edited and deleted a timer. Viewed a timer and toggled chrome mode.
Viewed timer list.
Reviewed By: hsb
Reviewers: hsb, aran, jungejason, tuomaspelkonen
CC: aran, hsb, epriestley
Differential Revision: 454
2011-06-14 02:35:13 +02:00
|
|
|
}
|
|
|
|
|
2015-04-13 19:30:13 +02:00
|
|
|
$classes = array();
|
|
|
|
$classes[] = 'main-page-frame';
|
2012-01-04 16:35:52 +01:00
|
|
|
$developer_warning = null;
|
2013-02-01 18:34:06 +01:00
|
|
|
if (PhabricatorEnv::getEnvConfig('phabricator.developer-mode') &&
|
2012-01-04 16:35:52 +01:00
|
|
|
DarkConsoleErrorLogPluginAPI::getErrors()) {
|
2013-11-09 19:48:19 +01:00
|
|
|
$developer_warning = phutil_tag_div(
|
|
|
|
'aphront-developer-error-callout',
|
2013-01-29 03:42:57 +01:00
|
|
|
pht(
|
|
|
|
'This page raised PHP errors. Find them in DarkConsole '.
|
|
|
|
'or the error log.'));
|
2012-01-04 16:35:52 +01:00
|
|
|
}
|
|
|
|
|
2013-01-18 01:25:47 +01:00
|
|
|
// Render the "you have unresolved setup issues..." warning.
|
|
|
|
$setup_warning = null;
|
|
|
|
if ($user && $user->getIsAdmin()) {
|
2015-02-11 22:00:59 +01:00
|
|
|
$open = PhabricatorSetupCheck::getOpenSetupIssueKeys();
|
2013-01-19 17:39:27 +01:00
|
|
|
if ($open) {
|
2015-04-13 19:30:13 +02:00
|
|
|
$classes[] = 'page-has-warning';
|
2013-11-09 19:48:19 +01:00
|
|
|
$setup_warning = phutil_tag_div(
|
|
|
|
'setup-warning-callout',
|
2013-01-25 14:50:50 +01:00
|
|
|
phutil_tag(
|
2013-01-19 17:39:27 +01:00
|
|
|
'a',
|
2013-01-18 01:25:47 +01:00
|
|
|
array(
|
2013-01-19 17:39:27 +01:00
|
|
|
'href' => '/config/issue/',
|
2015-02-11 22:00:59 +01:00
|
|
|
'title' => implode(', ', $open),
|
2013-01-18 01:25:47 +01:00
|
|
|
),
|
2015-02-11 22:00:59 +01:00
|
|
|
pht('You have %d unresolved setup issue(s)...', count($open))));
|
2013-01-18 01:25:47 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-23 22:29:15 +01:00
|
|
|
Javelin::initBehavior(
|
|
|
|
'scrollbar',
|
|
|
|
array(
|
|
|
|
'nodeID' => 'phabricator-standard-page',
|
2015-01-25 17:42:40 +01:00
|
|
|
'isMainContent' => true,
|
2015-01-23 22:29:15 +01:00
|
|
|
));
|
|
|
|
|
|
|
|
$main_page = phutil_tag(
|
2014-09-10 23:44:34 +02:00
|
|
|
'div',
|
|
|
|
array(
|
2015-01-23 22:29:15 +01:00
|
|
|
'id' => 'phabricator-standard-page',
|
2014-09-10 23:44:34 +02:00
|
|
|
'class' => 'phabricator-standard-page',
|
|
|
|
),
|
|
|
|
array(
|
Move setup issue callout to under the header
Summary: Fixes T7830. Moves the callout to sit under the main header, which resolved Differential issues and Durable Column issues, but still some extra CSS shenanigans.
Test Plan:
Test lots of pages, Home, Dashboards, Conpherence, Durable Column, Inline Diff Replies, Mobile, Workboards, etc.
{F375821}
{F375822}
{F375823}
Reviewers: btrahan, epriestley
Reviewed By: epriestley
Subscribers: Korvin, epriestley
Maniphest Tasks: T7830
Differential Revision: https://secure.phabricator.com/D12466
2015-04-19 16:15:59 +02:00
|
|
|
$developer_warning,
|
2014-09-10 23:44:34 +02:00
|
|
|
$header_chrome,
|
Move setup issue callout to under the header
Summary: Fixes T7830. Moves the callout to sit under the main header, which resolved Differential issues and Durable Column issues, but still some extra CSS shenanigans.
Test Plan:
Test lots of pages, Home, Dashboards, Conpherence, Durable Column, Inline Diff Replies, Mobile, Workboards, etc.
{F375821}
{F375822}
{F375823}
Reviewers: btrahan, epriestley
Reviewed By: epriestley
Subscribers: Korvin, epriestley
Maniphest Tasks: T7830
Differential Revision: https://secure.phabricator.com/D12466
2015-04-19 16:15:59 +02:00
|
|
|
$setup_warning,
|
Quicksand, an ignoble successor to Quickling
Summary:
Ref T2086. Ref T7014. With the persistent column, there is significant value in retaining chrome state through navigation events, because the user may have a lot of state in the chat window (scroll position, text selection, room juggling, partially entered text, etc). We can do this by capturing navigation events and faking them with Javascript.
(This can also improve performance, albeit slightly, and I believe there are better approaches to tackle performance any problems which exist with the chrome in many cases).
At Facebook, this system was "Photostream" in photos and then "Quickling" in general, and the technical cost of the system was //staggering//. I am loathe to pursue it again. However:
- Browsers are less junky now, and we target a smaller set of browsers. A large part of the technical cost of Quickling was the high complexity of emulating nagivation events in IE, where we needed to navigate a hidden iframe to make history entries. All desktop browsers which we might want to use this system on support the History API (although this prototype does not yet implement it).
- Javelin and Phabricator's architecture are much cleaner than Facebook's was. A large part of the technical cost of Quickling was inconsistency, inlined `onclick` handlers, and general lack of coordination and abstraction. We will have //some// of this, but "correctly written" behaviors are mostly immune to it by design, and many of Javelin's architectural decisions were influenced by desire to avoid issues we encountered building this stuff for Facebook.
- Some of the primitives which Quickling required (like loading resources over Ajax) have existed in a stable state in our codebase for a year or more, and adoption of these primitives was trivial and uneventful (vs a huge production at Facebook).
- My hubris is bolstered by recent success with WebSockets and JX.Scrollbar, both of which I would have assessed as infeasibly complex to develop in this project a few years ago.
To these points, the developer cost to prototype Photostream was several weeks; the developer cost to prototype this was a bit less than an hour. It is plausible to me that implementing and maintaining this system really will be hundreds of times less complex than it was at Facebook.
Test Plan:
My plan for this and D11497 is:
- Get them in master.
- Some secret key / relatively-hidden preference activates the column.
- Quicksand activates //only// when the column is open.
- We can use column + quicksand for a long period of time (i.e., over the course of Conpherence v2 development) and hammer out the long tail of issues.
- When it derps up, you just hide the column and you're good to go.
Reviewers: btrahan, chad
Reviewed By: chad
Subscribers: epriestley
Maniphest Tasks: T2086, T7014
Differential Revision: https://secure.phabricator.com/D11507
2015-01-27 23:52:09 +01:00
|
|
|
phutil_tag(
|
|
|
|
'div',
|
|
|
|
array(
|
|
|
|
'id' => 'phabricator-standard-page-body',
|
|
|
|
'class' => 'phabricator-standard-page-body',
|
|
|
|
),
|
|
|
|
$this->renderPageBodyContent()),
|
2014-09-10 23:44:34 +02:00
|
|
|
));
|
2015-01-23 22:29:15 +01:00
|
|
|
|
2015-01-27 15:30:52 +01:00
|
|
|
$durable_column = null;
|
|
|
|
if ($this->getShowDurableColumn()) {
|
2015-03-11 02:46:16 +01:00
|
|
|
$is_visible = $this->getDurableColumnVisible();
|
Conpherence - make the durable column kind of work and stuff
Summary:
Ref T7014. This hooks up the durable column such that when you open it up it loads your most recent Conpherence. You can then switch amongst the various widgets and stuff and everything works nicely.
Except...
- scroll bar does not work
- also doesn't work at HEAD when I add a ton of text to the UI with no changes? (wrapped $copy in array_fill(0, 1000, $copy))
- "widget selector" does not collapse when you select something else
- this part wasn't really specified so I used the aphlict dropdown stuff. didn't want to keep working on that if this was the wrong UI choice
- can not edit title
- do we still want that to be done by clicking on the title, which pops a dialogue?
- can not add participants or calendar events
- what should this UI be? maybe just a button on the top for "participants" and a button on the bottom for calendar? both on top?
- this is not pixel perfect to the mock or two I've seen around. Aside from generally being bad at that, I definitely didn't get the name + timestamps formatting correctly, because the standard DOM of that has timestamp FIRST which appears second due to a "float right". Seemed like a lot of special-casing for what might not even be that important in the UI so I punted. (And again, there's likely many unknown ways in which this isn't pixel perfect)
There's also code quality issues
- `ConpherenceWidgetConfigConstants` is hopefully temporary or at least gets more sleek as we keep progressing here
- copied some CSS from main Conpherence app
- DOM structure is pretty different
- there's some minor CSS tweaks too given the different width (not to mention the DOM structure being different)
- copied some JS from behavior-pontificate.js to sync threads relative to aphlict updates
- JS in general is like a better version of existing JS; these should collapse I'd hope?
- maybe the aphlict-behavior-dropdown change was badsauce?
...but all that said, this definitely feels really nice and I feel like adding stuff is going to be really easy compared to how normal Conpherence is.
Also includes a bonus bug fix - we now correctly update participation. The user would encounter this issue if they were in a conpherence that got some updates and then they went to a different page; they would have unread status for the messages that were ajax'd in. This patch fixes that by making sure we mark participation up to date with the proper transaction in all cases.
Test Plan: hit "\" to invoke the column and saw nice loading UI and my latest conpherence load. sent messages and verified they received A-OK by looking in DOM console. toggled various widges and verified they rendered correctly. opened up a second browser with a second user on the thread, sent a message, and it was received in a nice asynchronous fashion
Reviewers: chad, epriestley
Reviewed By: epriestley
Subscribers: Korvin, epriestley
Maniphest Tasks: T7014
Differential Revision: https://secure.phabricator.com/D11968
2015-03-05 19:33:39 +01:00
|
|
|
$durable_column = id(new ConpherenceDurableColumnView())
|
|
|
|
->setSelectedConpherence(null)
|
2015-03-11 02:46:16 +01:00
|
|
|
->setUser($user)
|
2015-04-21 00:44:14 +02:00
|
|
|
->setQuicksandConfig($this->buildQuicksandConfig())
|
2015-03-12 00:20:13 +01:00
|
|
|
->setVisible($is_visible)
|
|
|
|
->setInitialLoad(true);
|
2015-01-27 15:30:52 +01:00
|
|
|
}
|
|
|
|
|
2015-03-10 23:32:15 +01:00
|
|
|
Javelin::initBehavior('quicksand-blacklist', array(
|
|
|
|
'patterns' => $this->getQuicksandURIPatternBlacklist(),
|
|
|
|
));
|
|
|
|
|
2015-01-23 22:29:15 +01:00
|
|
|
return phutil_tag(
|
|
|
|
'div',
|
|
|
|
array(
|
2015-04-13 19:30:13 +02:00
|
|
|
'class' => implode(' ', $classes),
|
2015-01-23 22:29:15 +01:00
|
|
|
),
|
|
|
|
array(
|
|
|
|
$main_page,
|
2015-01-27 15:30:52 +01:00
|
|
|
$durable_column,
|
2015-01-23 22:29:15 +01:00
|
|
|
));
|
2011-01-16 22:51:39 +01:00
|
|
|
}
|
|
|
|
|
Quicksand, an ignoble successor to Quickling
Summary:
Ref T2086. Ref T7014. With the persistent column, there is significant value in retaining chrome state through navigation events, because the user may have a lot of state in the chat window (scroll position, text selection, room juggling, partially entered text, etc). We can do this by capturing navigation events and faking them with Javascript.
(This can also improve performance, albeit slightly, and I believe there are better approaches to tackle performance any problems which exist with the chrome in many cases).
At Facebook, this system was "Photostream" in photos and then "Quickling" in general, and the technical cost of the system was //staggering//. I am loathe to pursue it again. However:
- Browsers are less junky now, and we target a smaller set of browsers. A large part of the technical cost of Quickling was the high complexity of emulating nagivation events in IE, where we needed to navigate a hidden iframe to make history entries. All desktop browsers which we might want to use this system on support the History API (although this prototype does not yet implement it).
- Javelin and Phabricator's architecture are much cleaner than Facebook's was. A large part of the technical cost of Quickling was inconsistency, inlined `onclick` handlers, and general lack of coordination and abstraction. We will have //some// of this, but "correctly written" behaviors are mostly immune to it by design, and many of Javelin's architectural decisions were influenced by desire to avoid issues we encountered building this stuff for Facebook.
- Some of the primitives which Quickling required (like loading resources over Ajax) have existed in a stable state in our codebase for a year or more, and adoption of these primitives was trivial and uneventful (vs a huge production at Facebook).
- My hubris is bolstered by recent success with WebSockets and JX.Scrollbar, both of which I would have assessed as infeasibly complex to develop in this project a few years ago.
To these points, the developer cost to prototype Photostream was several weeks; the developer cost to prototype this was a bit less than an hour. It is plausible to me that implementing and maintaining this system really will be hundreds of times less complex than it was at Facebook.
Test Plan:
My plan for this and D11497 is:
- Get them in master.
- Some secret key / relatively-hidden preference activates the column.
- Quicksand activates //only// when the column is open.
- We can use column + quicksand for a long period of time (i.e., over the course of Conpherence v2 development) and hammer out the long tail of issues.
- When it derps up, you just hide the column and you're good to go.
Reviewers: btrahan, chad
Reviewed By: chad
Subscribers: epriestley
Maniphest Tasks: T2086, T7014
Differential Revision: https://secure.phabricator.com/D11507
2015-01-27 23:52:09 +01:00
|
|
|
private function renderPageBodyContent() {
|
|
|
|
$console = $this->getConsole();
|
|
|
|
|
|
|
|
return array(
|
|
|
|
($console ? hsprintf('<darkconsole />') : null),
|
|
|
|
parent::getBody(),
|
|
|
|
$this->renderFooter(),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2011-01-16 22:51:39 +01:00
|
|
|
protected function getTail() {
|
2012-07-31 01:09:14 +02:00
|
|
|
$request = $this->getRequest();
|
|
|
|
$user = $request->getUser();
|
|
|
|
|
2014-06-07 22:05:01 +02:00
|
|
|
$tail = array(
|
|
|
|
parent::getTail(),
|
|
|
|
);
|
2012-07-31 01:09:14 +02:00
|
|
|
|
2014-06-07 23:04:52 +02:00
|
|
|
$response = CelerityAPI::getStaticResourceResponse();
|
|
|
|
|
2014-06-07 22:05:01 +02:00
|
|
|
if (PhabricatorEnv::getEnvConfig('notification.enabled')) {
|
|
|
|
if ($user && $user->isLoggedIn()) {
|
|
|
|
|
|
|
|
$client_uri = PhabricatorEnv::getEnvConfig('notification.client-uri');
|
|
|
|
$client_uri = new PhutilURI($client_uri);
|
|
|
|
if ($client_uri->getDomain() == 'localhost') {
|
|
|
|
$this_host = $this->getRequest()->getHost();
|
|
|
|
$this_host = new PhutilURI('http://'.$this_host.'/');
|
|
|
|
$client_uri->setDomain($this_host->getDomain());
|
|
|
|
}
|
|
|
|
|
Rewrite Aphlict to use Websockets
Summary:
Fixes T6559. No more flash, use Websockets. This is less aggressive than the earlier version, and retains more server logic.
- Support "wss".
- Make the client work.
- Remove "notification.user" entirely.
- Seems ok?
Test Plan:
In Safari, Firefox and Chrome, saw the browsers connect. Made a bunch of comments/updates and saw notifications.
Notable holes in the test plan:
- Haven't tested "wss" yet. I'll do this on secure.
- Notifications are //too fast// now, locally. I get them after I hit submit but before the page reloads.
- There are probably some other rough edges, this is a fairly big patch.
Reviewers: joshuaspence, btrahan
Reviewed By: joshuaspence, btrahan
Subscribers: fabe, btrahan, epriestley
Maniphest Tasks: T6713, T6559
Differential Revision: https://secure.phabricator.com/D11143
2015-01-08 19:03:00 +01:00
|
|
|
if ($request->isHTTPS()) {
|
|
|
|
$client_uri->setProtocol('wss');
|
|
|
|
} else {
|
|
|
|
$client_uri->setProtocol('ws');
|
|
|
|
}
|
|
|
|
|
2014-06-07 22:05:01 +02:00
|
|
|
Javelin::initBehavior(
|
|
|
|
'aphlict-listen',
|
|
|
|
array(
|
Rewrite Aphlict to use Websockets
Summary:
Fixes T6559. No more flash, use Websockets. This is less aggressive than the earlier version, and retains more server logic.
- Support "wss".
- Make the client work.
- Remove "notification.user" entirely.
- Seems ok?
Test Plan:
In Safari, Firefox and Chrome, saw the browsers connect. Made a bunch of comments/updates and saw notifications.
Notable holes in the test plan:
- Haven't tested "wss" yet. I'll do this on secure.
- Notifications are //too fast// now, locally. I get them after I hit submit but before the page reloads.
- There are probably some other rough edges, this is a fairly big patch.
Reviewers: joshuaspence, btrahan
Reviewed By: joshuaspence, btrahan
Subscribers: fabe, btrahan, epriestley
Maniphest Tasks: T6713, T6559
Differential Revision: https://secure.phabricator.com/D11143
2015-01-08 19:03:00 +01:00
|
|
|
'websocketURI' => (string)$client_uri,
|
2015-04-21 01:43:32 +02:00
|
|
|
) + $this->buildAphlictListenConfigData());
|
2014-06-07 22:05:01 +02:00
|
|
|
}
|
2012-07-31 01:09:14 +02:00
|
|
|
}
|
|
|
|
|
2014-06-07 22:05:01 +02:00
|
|
|
$tail[] = $response->renderHTMLFooter();
|
2012-10-16 19:33:47 +02:00
|
|
|
|
2014-06-07 22:05:01 +02:00
|
|
|
return $tail;
|
2011-01-16 22:51:39 +01:00
|
|
|
}
|
|
|
|
|
Countdown tweaks
Summary:
A few tweaks to hsb's Countdown implementation:
- Allow the page to be rendered "chromeless", suitable for display on one of
the dozens of monitors everyone has laying around.
- Show title of countdown in deletion dialog.
- When creating a new countdown default to time(), not Dec 31, 1969.
- Add extra "/" after editing to avoid needless redirect.
- Tweak some page titles.
- Show countdown author in list view.
- Highlight tab in list view.
- Tweak menu copy.
- Link countdown title in list view, separate buttons into different columns
so they pick up padding.
Test Plan:
Created, edited and deleted a timer. Viewed a timer and toggled chrome mode.
Viewed timer list.
Reviewed By: hsb
Reviewers: hsb, aran, jungejason, tuomaspelkonen
CC: aran, hsb, epriestley
Differential Revision: 454
2011-06-14 02:35:13 +02:00
|
|
|
protected function getBodyClasses() {
|
|
|
|
$classes = array();
|
|
|
|
|
|
|
|
if (!$this->getShowChrome()) {
|
|
|
|
$classes[] = 'phabricator-chromeless-page';
|
|
|
|
}
|
|
|
|
|
2013-02-10 00:01:57 +01:00
|
|
|
$agent = AphrontRequest::getHTTPHeader('User-Agent');
|
2012-12-11 23:01:51 +01:00
|
|
|
|
|
|
|
// Try to guess the device resolution based on UA strings to avoid a flash
|
|
|
|
// of incorrectly-styled content.
|
|
|
|
$device_guess = 'device-desktop';
|
|
|
|
if (preg_match('@iPhone|iPod|(Android.*Chrome/[.0-9]* Mobile)@', $agent)) {
|
|
|
|
$device_guess = 'device-phone device';
|
|
|
|
} else if (preg_match('@iPad|(Android.*Chrome/)@', $agent)) {
|
|
|
|
$device_guess = 'device-tablet device';
|
|
|
|
}
|
|
|
|
|
|
|
|
$classes[] = $device_guess;
|
|
|
|
|
2013-04-01 22:48:57 +02:00
|
|
|
if (preg_match('@Windows@', $agent)) {
|
|
|
|
$classes[] = 'platform-windows';
|
|
|
|
} else if (preg_match('@Macintosh@', $agent)) {
|
|
|
|
$classes[] = 'platform-mac';
|
|
|
|
} else if (preg_match('@X11@', $agent)) {
|
|
|
|
$classes[] = 'platform-linux';
|
|
|
|
}
|
|
|
|
|
2013-10-19 23:23:19 +02:00
|
|
|
if ($this->getRequest()->getStr('__print__')) {
|
|
|
|
$classes[] = 'printable';
|
|
|
|
}
|
|
|
|
|
Add support for aural-only and visual-only elements
Summary:
Ref T4843. This adds support to `javelin_tag()` for an `aural` attribute. When specified, `true` values mean "this content is aural-only", while `false` values mean "this content is not aural".
- I've attempted to find the best modern approaches for marking this content, but the `aural` attribute should let us change the mechanism later.
- Make the "beta" markers on application navigation visual only (see T4843). This information is of very low importance, the application navigation is accessed frequently, and the information is available on the application list.
- Partially convert the main navigation. This is mostly to test things, since I want to get more concrete feedback about approaches here.
- Add a `?__aural__=1` attribute, which renders the page with aural-only elements visible and visual-only elements colored.
Test Plan: {F146476}
Reviewers: btrahan, scp, chad
Reviewed By: chad
Subscribers: aklapper, qgil, epriestley
Maniphest Tasks: T4843
Differential Revision: https://secure.phabricator.com/D8830
2014-05-01 16:18:18 +02:00
|
|
|
if ($this->getRequest()->getStr('__aural__')) {
|
|
|
|
$classes[] = 'audible';
|
|
|
|
}
|
|
|
|
|
Countdown tweaks
Summary:
A few tweaks to hsb's Countdown implementation:
- Allow the page to be rendered "chromeless", suitable for display on one of
the dozens of monitors everyone has laying around.
- Show title of countdown in deletion dialog.
- When creating a new countdown default to time(), not Dec 31, 1969.
- Add extra "/" after editing to avoid needless redirect.
- Tweak some page titles.
- Show countdown author in list view.
- Highlight tab in list view.
- Tweak menu copy.
- Link countdown title in list view, separate buttons into different columns
so they pick up padding.
Test Plan:
Created, edited and deleted a timer. Viewed a timer and toggled chrome mode.
Viewed timer list.
Reviewed By: hsb
Reviewers: hsb, aran, jungejason, tuomaspelkonen
CC: aran, hsb, epriestley
Differential Revision: 454
2011-06-14 02:35:13 +02:00
|
|
|
return implode(' ', $classes);
|
|
|
|
}
|
|
|
|
|
2011-07-09 18:45:19 +02:00
|
|
|
private function getConsole() {
|
|
|
|
if ($this->disableConsole) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
return $this->getRequest()->getApplicationConfiguration()->getConsole();
|
|
|
|
}
|
2012-07-31 01:09:14 +02:00
|
|
|
|
2014-09-10 23:44:34 +02:00
|
|
|
private function renderFooter() {
|
|
|
|
if (!$this->getShowChrome()) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!$this->getShowFooter()) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
$items = PhabricatorEnv::getEnvConfig('ui.footer-items');
|
|
|
|
if (!$items) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
$foot = array();
|
|
|
|
foreach ($items as $item) {
|
|
|
|
$name = idx($item, 'name', pht('Unnamed Footer Item'));
|
|
|
|
|
|
|
|
$href = idx($item, 'href');
|
Improve granluarity and defaults of `security.allow-outbound-http`
Summary:
Ref T6755. This is a partial fix, but:
- Allow netblocks to be blacklisted instead of making the feature all-or-nothing.
- Default to disallow requests to all reserved private/local/special IP blocks. This should generally be a "safe" setting.
- Explain the risks better.
- Improve the errors rasied by Macro when failing.
- Removed `security.allow-outbound-http`, as it is superseded by this setting and is somewhat misleading.
- We still make outbound HTTP requests to OAuth.
- We still make outbound HTTP requests for repositories.
From a technical perspective:
- Separate URIs that are safe to link to or redirect to (basically, not "javascript://") from URIs that are safe to fetch (nothing in a private block).
- Add the default blacklist.
- Be more careful with response data in Macro fetching, and don't let the user see it if it isn't ultimately valid.
Additionally:
- I want to do this check before pulling repositories, but that's enough of a mess that it should go in a separate diff.
- The future implementation of T4190 needs to perform the fetch check.
Test Plan:
- Fetched a valid macro.
- Fetched a non-image, verified it didn't result in a viewable file.
- Fetched a private-ip-space image, got an error.
- Fetched a 404, got a useful-enough error without additional revealing response content (which is usually HTML anyway and not useful).
- Fetched a bad protocol, got an error.
- Linked to a local resource, a phriction page, a valid remote site, all worked.
- Linked to private IP space, which worked fine (we want to let you link and redierect to other private services, just not fetch them).
- Added and executed unit tests.
Reviewers: btrahan
Reviewed By: btrahan
Subscribers: epriestley
Maniphest Tasks: T6755
Differential Revision: https://secure.phabricator.com/D12136
2015-03-23 18:44:03 +01:00
|
|
|
if (!PhabricatorEnv::isValidURIForLink($href)) {
|
2014-09-10 23:44:34 +02:00
|
|
|
$href = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($href !== null) {
|
|
|
|
$tag = 'a';
|
|
|
|
} else {
|
|
|
|
$tag = 'span';
|
|
|
|
}
|
|
|
|
|
|
|
|
$foot[] = phutil_tag(
|
|
|
|
$tag,
|
|
|
|
array(
|
|
|
|
'href' => $href,
|
|
|
|
),
|
|
|
|
$name);
|
|
|
|
}
|
|
|
|
$foot = phutil_implode_html(" \xC2\xB7 ", $foot);
|
|
|
|
|
|
|
|
return phutil_tag(
|
|
|
|
'div',
|
|
|
|
array(
|
2014-09-24 18:10:28 +02:00
|
|
|
'class' => 'phabricator-standard-page-footer grouped',
|
2014-09-10 23:44:34 +02:00
|
|
|
),
|
|
|
|
$foot);
|
|
|
|
}
|
|
|
|
|
Quicksand, an ignoble successor to Quickling
Summary:
Ref T2086. Ref T7014. With the persistent column, there is significant value in retaining chrome state through navigation events, because the user may have a lot of state in the chat window (scroll position, text selection, room juggling, partially entered text, etc). We can do this by capturing navigation events and faking them with Javascript.
(This can also improve performance, albeit slightly, and I believe there are better approaches to tackle performance any problems which exist with the chrome in many cases).
At Facebook, this system was "Photostream" in photos and then "Quickling" in general, and the technical cost of the system was //staggering//. I am loathe to pursue it again. However:
- Browsers are less junky now, and we target a smaller set of browsers. A large part of the technical cost of Quickling was the high complexity of emulating nagivation events in IE, where we needed to navigate a hidden iframe to make history entries. All desktop browsers which we might want to use this system on support the History API (although this prototype does not yet implement it).
- Javelin and Phabricator's architecture are much cleaner than Facebook's was. A large part of the technical cost of Quickling was inconsistency, inlined `onclick` handlers, and general lack of coordination and abstraction. We will have //some// of this, but "correctly written" behaviors are mostly immune to it by design, and many of Javelin's architectural decisions were influenced by desire to avoid issues we encountered building this stuff for Facebook.
- Some of the primitives which Quickling required (like loading resources over Ajax) have existed in a stable state in our codebase for a year or more, and adoption of these primitives was trivial and uneventful (vs a huge production at Facebook).
- My hubris is bolstered by recent success with WebSockets and JX.Scrollbar, both of which I would have assessed as infeasibly complex to develop in this project a few years ago.
To these points, the developer cost to prototype Photostream was several weeks; the developer cost to prototype this was a bit less than an hour. It is plausible to me that implementing and maintaining this system really will be hundreds of times less complex than it was at Facebook.
Test Plan:
My plan for this and D11497 is:
- Get them in master.
- Some secret key / relatively-hidden preference activates the column.
- Quicksand activates //only// when the column is open.
- We can use column + quicksand for a long period of time (i.e., over the course of Conpherence v2 development) and hammer out the long tail of issues.
- When it derps up, you just hide the column and you're good to go.
Reviewers: btrahan, chad
Reviewed By: chad
Subscribers: epriestley
Maniphest Tasks: T2086, T7014
Differential Revision: https://secure.phabricator.com/D11507
2015-01-27 23:52:09 +01:00
|
|
|
public function renderForQuicksand() {
|
2015-03-28 14:54:04 +01:00
|
|
|
parent::willRenderPage();
|
Quicksand, an ignoble successor to Quickling
Summary:
Ref T2086. Ref T7014. With the persistent column, there is significant value in retaining chrome state through navigation events, because the user may have a lot of state in the chat window (scroll position, text selection, room juggling, partially entered text, etc). We can do this by capturing navigation events and faking them with Javascript.
(This can also improve performance, albeit slightly, and I believe there are better approaches to tackle performance any problems which exist with the chrome in many cases).
At Facebook, this system was "Photostream" in photos and then "Quickling" in general, and the technical cost of the system was //staggering//. I am loathe to pursue it again. However:
- Browsers are less junky now, and we target a smaller set of browsers. A large part of the technical cost of Quickling was the high complexity of emulating nagivation events in IE, where we needed to navigate a hidden iframe to make history entries. All desktop browsers which we might want to use this system on support the History API (although this prototype does not yet implement it).
- Javelin and Phabricator's architecture are much cleaner than Facebook's was. A large part of the technical cost of Quickling was inconsistency, inlined `onclick` handlers, and general lack of coordination and abstraction. We will have //some// of this, but "correctly written" behaviors are mostly immune to it by design, and many of Javelin's architectural decisions were influenced by desire to avoid issues we encountered building this stuff for Facebook.
- Some of the primitives which Quickling required (like loading resources over Ajax) have existed in a stable state in our codebase for a year or more, and adoption of these primitives was trivial and uneventful (vs a huge production at Facebook).
- My hubris is bolstered by recent success with WebSockets and JX.Scrollbar, both of which I would have assessed as infeasibly complex to develop in this project a few years ago.
To these points, the developer cost to prototype Photostream was several weeks; the developer cost to prototype this was a bit less than an hour. It is plausible to me that implementing and maintaining this system really will be hundreds of times less complex than it was at Facebook.
Test Plan:
My plan for this and D11497 is:
- Get them in master.
- Some secret key / relatively-hidden preference activates the column.
- Quicksand activates //only// when the column is open.
- We can use column + quicksand for a long period of time (i.e., over the course of Conpherence v2 development) and hammer out the long tail of issues.
- When it derps up, you just hide the column and you're good to go.
Reviewers: btrahan, chad
Reviewed By: chad
Subscribers: epriestley
Maniphest Tasks: T2086, T7014
Differential Revision: https://secure.phabricator.com/D11507
2015-01-27 23:52:09 +01:00
|
|
|
$response = $this->renderPageBodyContent();
|
|
|
|
$response = $this->willSendResponse($response);
|
|
|
|
|
|
|
|
return array(
|
|
|
|
'content' => hsprintf('%s', $response),
|
2015-04-21 00:44:14 +02:00
|
|
|
) + $this->buildQuicksandConfig();
|
|
|
|
}
|
|
|
|
|
|
|
|
private function buildQuicksandConfig() {
|
2015-04-21 20:01:05 +02:00
|
|
|
return array(
|
|
|
|
'title' => $this->getTitle(),
|
|
|
|
) + $this->buildAphlictListenConfigData();
|
2015-04-21 01:43:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private function buildAphlictListenConfigData() {
|
|
|
|
$user = $this->getRequest()->getUser();
|
|
|
|
$subscriptions = $this->pageObjects;
|
|
|
|
$subscriptions[] = $user->getPHID();
|
|
|
|
|
|
|
|
return array(
|
|
|
|
'pageObjects' => array_fill_keys($this->pageObjects, true),
|
|
|
|
'subscriptions' => $subscriptions,
|
|
|
|
);
|
Quicksand, an ignoble successor to Quickling
Summary:
Ref T2086. Ref T7014. With the persistent column, there is significant value in retaining chrome state through navigation events, because the user may have a lot of state in the chat window (scroll position, text selection, room juggling, partially entered text, etc). We can do this by capturing navigation events and faking them with Javascript.
(This can also improve performance, albeit slightly, and I believe there are better approaches to tackle performance any problems which exist with the chrome in many cases).
At Facebook, this system was "Photostream" in photos and then "Quickling" in general, and the technical cost of the system was //staggering//. I am loathe to pursue it again. However:
- Browsers are less junky now, and we target a smaller set of browsers. A large part of the technical cost of Quickling was the high complexity of emulating nagivation events in IE, where we needed to navigate a hidden iframe to make history entries. All desktop browsers which we might want to use this system on support the History API (although this prototype does not yet implement it).
- Javelin and Phabricator's architecture are much cleaner than Facebook's was. A large part of the technical cost of Quickling was inconsistency, inlined `onclick` handlers, and general lack of coordination and abstraction. We will have //some// of this, but "correctly written" behaviors are mostly immune to it by design, and many of Javelin's architectural decisions were influenced by desire to avoid issues we encountered building this stuff for Facebook.
- Some of the primitives which Quickling required (like loading resources over Ajax) have existed in a stable state in our codebase for a year or more, and adoption of these primitives was trivial and uneventful (vs a huge production at Facebook).
- My hubris is bolstered by recent success with WebSockets and JX.Scrollbar, both of which I would have assessed as infeasibly complex to develop in this project a few years ago.
To these points, the developer cost to prototype Photostream was several weeks; the developer cost to prototype this was a bit less than an hour. It is plausible to me that implementing and maintaining this system really will be hundreds of times less complex than it was at Facebook.
Test Plan:
My plan for this and D11497 is:
- Get them in master.
- Some secret key / relatively-hidden preference activates the column.
- Quicksand activates //only// when the column is open.
- We can use column + quicksand for a long period of time (i.e., over the course of Conpherence v2 development) and hammer out the long tail of issues.
- When it derps up, you just hide the column and you're good to go.
Reviewers: btrahan, chad
Reviewed By: chad
Subscribers: epriestley
Maniphest Tasks: T2086, T7014
Differential Revision: https://secure.phabricator.com/D11507
2015-01-27 23:52:09 +01:00
|
|
|
}
|
2015-03-10 23:32:15 +01:00
|
|
|
|
|
|
|
private function getQuicksandURIPatternBlacklist() {
|
|
|
|
$applications = PhabricatorApplication::getAllApplications();
|
|
|
|
|
|
|
|
$blacklist = array();
|
|
|
|
foreach ($applications as $application) {
|
|
|
|
$blacklist[] = $application->getQuicksandURIPatternBlacklist();
|
|
|
|
}
|
|
|
|
|
|
|
|
return array_mergev($blacklist);
|
|
|
|
}
|
|
|
|
|
2015-03-11 02:46:16 +01:00
|
|
|
private function getUserPreference($key, $default = null) {
|
|
|
|
$request = $this->getRequest();
|
|
|
|
if (!$request) {
|
|
|
|
return $default;
|
|
|
|
}
|
|
|
|
|
|
|
|
$user = $request->getUser();
|
|
|
|
if (!$user) {
|
|
|
|
return $default;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $user->loadPreferences()->getPreference($key, $default);
|
|
|
|
}
|
|
|
|
|
2011-01-16 22:51:39 +01:00
|
|
|
}
|