mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-26 00:32:42 +01:00
Provide a global router for Ajax requests
Summary: Fixes T430. Fixes T4834. Obsoletes D7641. Currently, we do some things less-well than we could: - We just let the browser queue and prioritize requests, so if you load a revision with 50 changes and then click "Award Token", the action blocks until the changes load in most/all browsers. It would be better to prioritize this action and queue it immediately. - Similarly, changes tend to load in order, even if the user has clicked to a specific file. When the user expresses a preference for a specific file, we should prioritize it. - We show a spinning GIF when waiting on requests. This is appropriate for some types of reuqests, but distracting for others. To fix this: - Queue all (or, at least, most) requests into a new queue in JX.Router. - JX.Router handles prioritizing the requests. Principally: - You can submit a request with a specific priority (500 = general content loading, 1000 = default, 2000 = explicit user action) and JX.Router will get the higher stuff fired off sooner. - You can name requests and then adjust their prorities later, if the user expresses an interest in specific results. - Only use the spinner gif for "workflow" requests, which is bascially when the user clicked something and we're waiting on the server. I think it's useful and not-annoying in this case. - Don't show any status for draft requests. - For content requests, show a subtle hipster-style top loading bar. Test Plan: - Viewed a diff with 93 changes, and clicked award token. - Prior to this patch, the action took many many seconds to resolve. - After this patch, it resolves quickly. - Viewed a diff with 93 changes and saw a pleasant subtle hipster-style loading bar. - Viewed a diff with 93 changes and typed some draft text. Previews populated fairly quickly and there was no spinner. - Viewed a diff with 93 changes and clicked something with workflow, saw a spinner after a moment. - Viewed a diff with 93 changes and clicked a file in the table of contents near the end of the list. - Prior to this patch, it took a long time to show up. - After this patch, it loads directly. Reviewers: chad, btrahan Reviewed By: btrahan Subscribers: epriestley Maniphest Tasks: T430, T4834 Differential Revision: https://secure.phabricator.com/D8979
This commit is contained in:
parent
bfc1ccfdf1
commit
2b4c551b0e
11 changed files with 469 additions and 104 deletions
|
@ -7,14 +7,14 @@
|
|||
return array(
|
||||
'names' =>
|
||||
array(
|
||||
'core.pkg.css' => '4279f4bd',
|
||||
'core.pkg.js' => 'f6616bcf',
|
||||
'core.pkg.css' => '989eee69',
|
||||
'core.pkg.js' => 'b2ed04a2',
|
||||
'darkconsole.pkg.js' => 'ca8671ce',
|
||||
'differential.pkg.css' => '4b8686e3',
|
||||
'differential.pkg.js' => 'a2f45b5f',
|
||||
'differential.pkg.js' => '05ad02d3',
|
||||
'diffusion.pkg.css' => '3783278d',
|
||||
'diffusion.pkg.js' => '5b4010f4',
|
||||
'javelin.pkg.js' => 'c57fd32c',
|
||||
'javelin.pkg.js' => 'dbef0389',
|
||||
'maniphest.pkg.css' => 'f1887d71',
|
||||
'maniphest.pkg.js' => '2fe8af22',
|
||||
'rsrc/css/aphront/aphront-bars.css' => '231ac33c',
|
||||
|
@ -105,7 +105,7 @@ return array(
|
|||
'rsrc/css/application/subscriptions/subscribers-list.css' => '5bb30c78',
|
||||
'rsrc/css/application/tokens/tokens.css' => '3d0f239e',
|
||||
'rsrc/css/application/uiexample/example.css' => '528b19de',
|
||||
'rsrc/css/core/core.css' => 'ef1b7892',
|
||||
'rsrc/css/core/core.css' => '40151074',
|
||||
'rsrc/css/core/remarkup.css' => '80c3a48c',
|
||||
'rsrc/css/core/syntax.css' => '3c18c1cb',
|
||||
'rsrc/css/core/z-index.css' => 'efb673ac',
|
||||
|
@ -204,11 +204,13 @@ return array(
|
|||
'rsrc/externals/javelin/lib/History.js' => 'c60f4327',
|
||||
'rsrc/externals/javelin/lib/JSON.js' => '08e56a4e',
|
||||
'rsrc/externals/javelin/lib/Mask.js' => 'b9f26029',
|
||||
'rsrc/externals/javelin/lib/Request.js' => '23f9bb8d',
|
||||
'rsrc/externals/javelin/lib/Request.js' => '7bad574b',
|
||||
'rsrc/externals/javelin/lib/Resource.js' => '356de121',
|
||||
'rsrc/externals/javelin/lib/Routable.js' => 'b3e7d692',
|
||||
'rsrc/externals/javelin/lib/Router.js' => '29274e2b',
|
||||
'rsrc/externals/javelin/lib/URI.js' => 'd9a9b862',
|
||||
'rsrc/externals/javelin/lib/Vector.js' => '039fb90d',
|
||||
'rsrc/externals/javelin/lib/Workflow.js' => 'ff8091f7',
|
||||
'rsrc/externals/javelin/lib/Workflow.js' => '09b15cf1',
|
||||
'rsrc/externals/javelin/lib/__tests__/Cookie.js' => '5ed109e8',
|
||||
'rsrc/externals/javelin/lib/__tests__/DOM.js' => 'c984504b',
|
||||
'rsrc/externals/javelin/lib/__tests__/JSON.js' => '2295d074',
|
||||
|
@ -349,7 +351,7 @@ return array(
|
|||
'rsrc/image/texture/table_header_tall.png' => 'd56b434f',
|
||||
'rsrc/js/application/aphlict/Aphlict.js' => '493665ee',
|
||||
'rsrc/js/application/aphlict/behavior-aphlict-dropdown.js' => '2a2dba85',
|
||||
'rsrc/js/application/aphlict/behavior-aphlict-listen.js' => '845731b8',
|
||||
'rsrc/js/application/aphlict/behavior-aphlict-listen.js' => '0a6c2de6',
|
||||
'rsrc/js/application/auth/behavior-persona-login.js' => '9414ff18',
|
||||
'rsrc/js/application/config/behavior-reorder-fields.js' => '938aed89',
|
||||
'rsrc/js/application/conpherence/behavior-menu.js' => '7ee23816',
|
||||
|
@ -365,7 +367,7 @@ return array(
|
|||
'rsrc/js/application/differential/behavior-dropdown-menus.js' => '7f93ef26',
|
||||
'rsrc/js/application/differential/behavior-edit-inline-comments.js' => '00861799',
|
||||
'rsrc/js/application/differential/behavior-keyboard-nav.js' => '173ce7e7',
|
||||
'rsrc/js/application/differential/behavior-populate.js' => 'ce0c217a',
|
||||
'rsrc/js/application/differential/behavior-populate.js' => 'dfdf9f34',
|
||||
'rsrc/js/application/differential/behavior-show-all-comments.js' => '7c273581',
|
||||
'rsrc/js/application/differential/behavior-show-field-details.js' => '441f2137',
|
||||
'rsrc/js/application/differential/behavior-show-more.js' => 'dd7e8ef5',
|
||||
|
@ -438,7 +440,7 @@ return array(
|
|||
'rsrc/js/core/MultirowRowManager.js' => '50395a1b',
|
||||
'rsrc/js/core/Notification.js' => '0c6946e7',
|
||||
'rsrc/js/core/Prefab.js' => '0326e5d0',
|
||||
'rsrc/js/core/ShapedRequest.js' => 'dfa181a4',
|
||||
'rsrc/js/core/ShapedRequest.js' => '7cbe244b',
|
||||
'rsrc/js/core/TextAreaUtils.js' => 'b3ec3cfc',
|
||||
'rsrc/js/core/ToolTip.js' => '3915d490',
|
||||
'rsrc/js/core/behavior-active-nav.js' => 'c81bc98f',
|
||||
|
@ -467,7 +469,7 @@ return array(
|
|||
'rsrc/js/core/behavior-oncopy.js' => 'c3e218fe',
|
||||
'rsrc/js/core/behavior-phabricator-nav.js' => 'b5842a5e',
|
||||
'rsrc/js/core/behavior-phabricator-remarkup-assist.js' => 'c021950a',
|
||||
'rsrc/js/core/behavior-refresh-csrf.js' => 'c4b31646',
|
||||
'rsrc/js/core/behavior-refresh-csrf.js' => '7814b593',
|
||||
'rsrc/js/core/behavior-remarkup-preview.js' => 'f7379f45',
|
||||
'rsrc/js/core/behavior-reveal-content.js' => '8f24abfc',
|
||||
'rsrc/js/core/behavior-search-typeahead.js' => 'd8469741',
|
||||
|
@ -476,7 +478,7 @@ return array(
|
|||
'rsrc/js/core/behavior-tokenizer.js' => 'b3a4b884',
|
||||
'rsrc/js/core/behavior-tooltip.js' => '48db4145',
|
||||
'rsrc/js/core/behavior-watch-anchor.js' => '06e05112',
|
||||
'rsrc/js/core/behavior-workflow.js' => 'fee00761',
|
||||
'rsrc/js/core/behavior-workflow.js' => '0a3f3021',
|
||||
'rsrc/js/core/phtize.js' => 'd254d646',
|
||||
'rsrc/js/phui/behavior-phui-object-box-tabs.js' => 'a3e2244e',
|
||||
'rsrc/js/phui/behavior-phui-timeline-dropdown-menu.js' => '4d94d9c3',
|
||||
|
@ -534,7 +536,7 @@ return array(
|
|||
'javelin-aphlict' => '493665ee',
|
||||
'javelin-behavior' => '8a3ed18b',
|
||||
'javelin-behavior-aphlict-dropdown' => '2a2dba85',
|
||||
'javelin-behavior-aphlict-listen' => '845731b8',
|
||||
'javelin-behavior-aphlict-listen' => '0a6c2de6',
|
||||
'javelin-behavior-aphront-basic-tokenizer' => 'b3a4b884',
|
||||
'javelin-behavior-aphront-crop' => 'b98fc918',
|
||||
'javelin-behavior-aphront-drag-and-drop-textarea' => '4a11ea9c',
|
||||
|
@ -558,7 +560,7 @@ return array(
|
|||
'javelin-behavior-differential-edit-inline-comments' => '00861799',
|
||||
'javelin-behavior-differential-feedback-preview' => '127f2018',
|
||||
'javelin-behavior-differential-keyboard-navigation' => '173ce7e7',
|
||||
'javelin-behavior-differential-populate' => 'ce0c217a',
|
||||
'javelin-behavior-differential-populate' => 'dfdf9f34',
|
||||
'javelin-behavior-differential-show-field-details' => '441f2137',
|
||||
'javelin-behavior-differential-show-more' => 'dd7e8ef5',
|
||||
'javelin-behavior-differential-toggle-files' => 'ca3f91eb',
|
||||
|
@ -623,7 +625,7 @@ return array(
|
|||
'javelin-behavior-ponder-votebox' => '327dbe61',
|
||||
'javelin-behavior-project-boards' => 'd8e135db',
|
||||
'javelin-behavior-project-create' => '065227cc',
|
||||
'javelin-behavior-refresh-csrf' => 'c4b31646',
|
||||
'javelin-behavior-refresh-csrf' => '7814b593',
|
||||
'javelin-behavior-releeph-preview-branch' => '9eb2cedb',
|
||||
'javelin-behavior-releeph-request-state-change' => 'd259e7c9',
|
||||
'javelin-behavior-releeph-request-typeahead' => 'cd9e7094',
|
||||
|
@ -636,7 +638,7 @@ return array(
|
|||
'javelin-behavior-test-payment-form' => 'b3e5ee60',
|
||||
'javelin-behavior-toggle-class' => 'a82a7769',
|
||||
'javelin-behavior-view-placeholder' => '2fa810fc',
|
||||
'javelin-behavior-workflow' => 'fee00761',
|
||||
'javelin-behavior-workflow' => '0a3f3021',
|
||||
'javelin-color' => '7e41274a',
|
||||
'javelin-cookie' => '6b3dcf44',
|
||||
'javelin-dom' => '07d99a3d',
|
||||
|
@ -652,8 +654,10 @@ return array(
|
|||
'javelin-reactor-dom' => 'b6d401d6',
|
||||
'javelin-reactor-node-calmer' => '76f4ebed',
|
||||
'javelin-reactornode' => 'b4c30592',
|
||||
'javelin-request' => '23f9bb8d',
|
||||
'javelin-request' => '7bad574b',
|
||||
'javelin-resource' => '356de121',
|
||||
'javelin-routable' => 'b3e7d692',
|
||||
'javelin-router' => '29274e2b',
|
||||
'javelin-stratcom' => 'c293f7b9',
|
||||
'javelin-tokenizer' => 'e7c21fb3',
|
||||
'javelin-typeahead' => 'c54eeefb',
|
||||
|
@ -671,7 +675,7 @@ return array(
|
|||
'javelin-view-interpreter' => '0c33c1a0',
|
||||
'javelin-view-renderer' => '6c2b09a2',
|
||||
'javelin-view-visitor' => 'efe49472',
|
||||
'javelin-workflow' => 'ff8091f7',
|
||||
'javelin-workflow' => '09b15cf1',
|
||||
'lightbox-attachment-css' => '7acac05d',
|
||||
'maniphest-batch-editor' => '8f380ebc',
|
||||
'maniphest-report-css' => '6fc16517',
|
||||
|
@ -689,7 +693,7 @@ return array(
|
|||
'phabricator-busy' => '6453c869',
|
||||
'phabricator-chatlog-css' => '852140ff',
|
||||
'phabricator-content-source-view-css' => '4b8b05d4',
|
||||
'phabricator-core-css' => 'ef1b7892',
|
||||
'phabricator-core-css' => '40151074',
|
||||
'phabricator-countdown-css' => '86b7b0a0',
|
||||
'phabricator-crumbs-view-css' => '0222cbe0',
|
||||
'phabricator-drag-and-drop-file-upload' => 'ae6abfba',
|
||||
|
@ -717,7 +721,7 @@ return array(
|
|||
'phabricator-remarkup-css' => '80c3a48c',
|
||||
'phabricator-search-results-css' => 'f240504c',
|
||||
'phabricator-settings-css' => 'ea8f5915',
|
||||
'phabricator-shaped-request' => 'dfa181a4',
|
||||
'phabricator-shaped-request' => '7cbe244b',
|
||||
'phabricator-side-menu-view-css' => '503699d0',
|
||||
'phabricator-slowvote-css' => '266df6a1',
|
||||
'phabricator-source-code-view-css' => '62a99814',
|
||||
|
@ -879,6 +883,38 @@ return array(
|
|||
array(
|
||||
0 => 'javelin-install',
|
||||
),
|
||||
'09b15cf1' =>
|
||||
array(
|
||||
0 => 'javelin-stratcom',
|
||||
1 => 'javelin-request',
|
||||
2 => 'javelin-dom',
|
||||
3 => 'javelin-vector',
|
||||
4 => 'javelin-install',
|
||||
5 => 'javelin-util',
|
||||
6 => 'javelin-mask',
|
||||
7 => 'javelin-uri',
|
||||
8 => 'javelin-routable',
|
||||
),
|
||||
'0a3f3021' =>
|
||||
array(
|
||||
0 => 'javelin-behavior',
|
||||
1 => 'javelin-stratcom',
|
||||
2 => 'javelin-workflow',
|
||||
3 => 'javelin-dom',
|
||||
4 => 'javelin-router',
|
||||
),
|
||||
'0a6c2de6' =>
|
||||
array(
|
||||
0 => 'javelin-behavior',
|
||||
1 => 'javelin-aphlict',
|
||||
2 => 'javelin-stratcom',
|
||||
3 => 'javelin-request',
|
||||
4 => 'javelin-uri',
|
||||
5 => 'javelin-dom',
|
||||
6 => 'javelin-json',
|
||||
7 => 'javelin-router',
|
||||
8 => 'phabricator-notification',
|
||||
),
|
||||
'0c33c1a0' =>
|
||||
array(
|
||||
0 => 'javelin-view',
|
||||
|
@ -990,16 +1026,6 @@ return array(
|
|||
5 => 'javelin-json',
|
||||
6 => 'phabricator-prefab',
|
||||
),
|
||||
'23f9bb8d' =>
|
||||
array(
|
||||
0 => 'javelin-install',
|
||||
1 => 'javelin-stratcom',
|
||||
2 => 'javelin-util',
|
||||
3 => 'javelin-behavior',
|
||||
4 => 'javelin-json',
|
||||
5 => 'javelin-dom',
|
||||
6 => 'javelin-resource',
|
||||
),
|
||||
'263aeb8c' =>
|
||||
array(
|
||||
0 => 'javelin-behavior',
|
||||
|
@ -1012,6 +1038,11 @@ return array(
|
|||
7 => 'javelin-typeahead-preloaded-source',
|
||||
8 => 'javelin-json',
|
||||
),
|
||||
'29274e2b' =>
|
||||
array(
|
||||
0 => 'javelin-install',
|
||||
1 => 'javelin-util',
|
||||
),
|
||||
'2a2dba85' =>
|
||||
array(
|
||||
0 => 'javelin-behavior',
|
||||
|
@ -1223,6 +1254,11 @@ return array(
|
|||
2 => 'javelin-util',
|
||||
3 => 'phabricator-shaped-request',
|
||||
),
|
||||
'7319e029' =>
|
||||
array(
|
||||
0 => 'javelin-behavior',
|
||||
1 => 'javelin-dom',
|
||||
),
|
||||
'62e18640' =>
|
||||
array(
|
||||
0 => 'javelin-install',
|
||||
|
@ -1258,11 +1294,6 @@ return array(
|
|||
1 => 'javelin-stratcom',
|
||||
2 => 'javelin-dom',
|
||||
),
|
||||
'7319e029' =>
|
||||
array(
|
||||
0 => 'javelin-behavior',
|
||||
1 => 'javelin-dom',
|
||||
),
|
||||
'75903ee1' =>
|
||||
array(
|
||||
0 => 'javelin-behavior',
|
||||
|
@ -1281,6 +1312,15 @@ return array(
|
|||
0 => 'javelin-install',
|
||||
1 => 'javelin-util',
|
||||
),
|
||||
'7814b593' =>
|
||||
array(
|
||||
0 => 'javelin-request',
|
||||
1 => 'javelin-behavior',
|
||||
2 => 'javelin-dom',
|
||||
3 => 'javelin-router',
|
||||
4 => 'javelin-util',
|
||||
5 => 'phabricator-busy',
|
||||
),
|
||||
'79473b62' =>
|
||||
array(
|
||||
0 => 'javelin-install',
|
||||
|
@ -1296,12 +1336,30 @@ return array(
|
|||
1 => 'javelin-dom',
|
||||
2 => 'javelin-reactor-dom',
|
||||
),
|
||||
'7bad574b' =>
|
||||
array(
|
||||
0 => 'javelin-install',
|
||||
1 => 'javelin-stratcom',
|
||||
2 => 'javelin-util',
|
||||
3 => 'javelin-behavior',
|
||||
4 => 'javelin-json',
|
||||
5 => 'javelin-dom',
|
||||
6 => 'javelin-resource',
|
||||
7 => 'javelin-routable',
|
||||
),
|
||||
'7c273581' =>
|
||||
array(
|
||||
0 => 'javelin-behavior',
|
||||
1 => 'javelin-stratcom',
|
||||
2 => 'javelin-dom',
|
||||
),
|
||||
'7cbe244b' =>
|
||||
array(
|
||||
0 => 'javelin-install',
|
||||
1 => 'javelin-util',
|
||||
2 => 'javelin-request',
|
||||
3 => 'javelin-router',
|
||||
),
|
||||
'7e41274a' =>
|
||||
array(
|
||||
0 => 'javelin-install',
|
||||
|
@ -1345,17 +1403,6 @@ return array(
|
|||
1 => 'javelin-dom',
|
||||
2 => 'javelin-reactor-dom',
|
||||
),
|
||||
'845731b8' =>
|
||||
array(
|
||||
0 => 'javelin-behavior',
|
||||
1 => 'javelin-aphlict',
|
||||
2 => 'javelin-stratcom',
|
||||
3 => 'javelin-request',
|
||||
4 => 'javelin-uri',
|
||||
5 => 'javelin-dom',
|
||||
6 => 'javelin-json',
|
||||
7 => 'phabricator-notification',
|
||||
),
|
||||
'84845b5b' =>
|
||||
array(
|
||||
0 => 'javelin-behavior',
|
||||
|
@ -1555,6 +1602,10 @@ return array(
|
|||
1 => 'javelin-dom',
|
||||
2 => 'phortune-credit-card-form',
|
||||
),
|
||||
'b3e7d692' =>
|
||||
array(
|
||||
0 => 'javelin-install',
|
||||
),
|
||||
'b3ec3cfc' =>
|
||||
array(
|
||||
0 => 'javelin-install',
|
||||
|
@ -1683,13 +1734,6 @@ return array(
|
|||
0 => 'javelin-behavior',
|
||||
1 => 'javelin-dom',
|
||||
),
|
||||
'c4b31646' =>
|
||||
array(
|
||||
0 => 'javelin-request',
|
||||
1 => 'javelin-behavior',
|
||||
2 => 'javelin-dom',
|
||||
3 => 'phabricator-busy',
|
||||
),
|
||||
'c51a6616' =>
|
||||
array(
|
||||
0 => 'phabricator-notification',
|
||||
|
@ -1744,17 +1788,6 @@ return array(
|
|||
0 => 'javelin-install',
|
||||
1 => 'javelin-typeahead-source',
|
||||
),
|
||||
'ce0c217a' =>
|
||||
array(
|
||||
0 => 'javelin-behavior',
|
||||
1 => 'javelin-workflow',
|
||||
2 => 'javelin-util',
|
||||
3 => 'javelin-dom',
|
||||
4 => 'javelin-stratcom',
|
||||
5 => 'javelin-behavior-device',
|
||||
6 => 'javelin-vector',
|
||||
7 => 'phabricator-tooltip',
|
||||
),
|
||||
'cf656c84' =>
|
||||
array(
|
||||
0 => 'javelin-behavior',
|
||||
|
@ -1848,11 +1881,17 @@ return array(
|
|||
1 => 'javelin-dom',
|
||||
2 => 'phabricator-prefab',
|
||||
),
|
||||
'dfa181a4' =>
|
||||
'dfdf9f34' =>
|
||||
array(
|
||||
0 => 'javelin-install',
|
||||
1 => 'javelin-util',
|
||||
2 => 'javelin-request',
|
||||
0 => 'javelin-behavior',
|
||||
1 => 'javelin-workflow',
|
||||
2 => 'javelin-util',
|
||||
3 => 'javelin-dom',
|
||||
4 => 'javelin-stratcom',
|
||||
5 => 'javelin-behavior-device',
|
||||
6 => 'javelin-vector',
|
||||
7 => 'javelin-router',
|
||||
8 => 'phabricator-tooltip',
|
||||
),
|
||||
'e1ff79b1' =>
|
||||
array(
|
||||
|
@ -1987,24 +2026,6 @@ return array(
|
|||
4 => 'multirow-row-manager',
|
||||
5 => 'javelin-json',
|
||||
),
|
||||
'fee00761' =>
|
||||
array(
|
||||
0 => 'javelin-behavior',
|
||||
1 => 'javelin-stratcom',
|
||||
2 => 'javelin-workflow',
|
||||
3 => 'javelin-dom',
|
||||
),
|
||||
'ff8091f7' =>
|
||||
array(
|
||||
0 => 'javelin-stratcom',
|
||||
1 => 'javelin-request',
|
||||
2 => 'javelin-dom',
|
||||
3 => 'javelin-vector',
|
||||
4 => 'javelin-install',
|
||||
5 => 'javelin-util',
|
||||
6 => 'javelin-mask',
|
||||
7 => 'javelin-uri',
|
||||
),
|
||||
28497740 =>
|
||||
array(
|
||||
0 => 'javelin-behavior',
|
||||
|
|
|
@ -159,3 +159,21 @@ hr {
|
|||
background: #990066;
|
||||
opacity: 0.25;
|
||||
}
|
||||
|
||||
.routing-bar {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 2px;
|
||||
background: {$darkbluetext};
|
||||
z-index: 80;
|
||||
box-shadow: 0 2px 1px rgba(0, 128, 255, 0.25);
|
||||
}
|
||||
|
||||
.routing-progress {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 2px;
|
||||
background: {$sky};
|
||||
}
|
||||
|
|
13
webroot/rsrc/externals/javelin/lib/Request.js
vendored
13
webroot/rsrc/externals/javelin/lib/Request.js
vendored
|
@ -6,6 +6,7 @@
|
|||
* javelin-json
|
||||
* javelin-dom
|
||||
* javelin-resource
|
||||
* javelin-routable
|
||||
* @provides javelin-request
|
||||
* @javelin
|
||||
*/
|
||||
|
@ -69,6 +70,18 @@ JX.install('Request', {
|
|||
return this._transport;
|
||||
},
|
||||
|
||||
getRoutable: function() {
|
||||
var routable = new JX.Routable();
|
||||
routable.listen('start', JX.bind(this, function() {
|
||||
// Pass the event to allow other listeners to "start" to configure this
|
||||
// request before it fires.
|
||||
JX.Stratcom.pass(JX.Stratcom.context());
|
||||
this.send();
|
||||
}));
|
||||
this.listen('finally', JX.bind(routable, routable.done));
|
||||
return routable;
|
||||
},
|
||||
|
||||
send : function() {
|
||||
if (this._sent || this._finished) {
|
||||
if (__DEV__) {
|
||||
|
|
41
webroot/rsrc/externals/javelin/lib/Routable.js
vendored
Normal file
41
webroot/rsrc/externals/javelin/lib/Routable.js
vendored
Normal file
|
@ -0,0 +1,41 @@
|
|||
/**
|
||||
* @provides javelin-routable
|
||||
* @requires javelin-install
|
||||
* @javelin
|
||||
*/
|
||||
|
||||
JX.install('Routable', {
|
||||
|
||||
construct : function() {
|
||||
this._id = (JX.Routable._nextID++);
|
||||
},
|
||||
|
||||
properties: {
|
||||
key: null,
|
||||
priority: 1000,
|
||||
type: 'default'
|
||||
},
|
||||
|
||||
events: ['start', 'done'],
|
||||
|
||||
members: {
|
||||
_id: null,
|
||||
|
||||
getID: function() {
|
||||
return this._id;
|
||||
},
|
||||
|
||||
start: function() {
|
||||
this.invoke('start');
|
||||
},
|
||||
|
||||
done: function() {
|
||||
this.invoke('done');
|
||||
}
|
||||
},
|
||||
|
||||
statics: {
|
||||
_nextID: 0
|
||||
}
|
||||
|
||||
});
|
115
webroot/rsrc/externals/javelin/lib/Router.js
vendored
Normal file
115
webroot/rsrc/externals/javelin/lib/Router.js
vendored
Normal file
|
@ -0,0 +1,115 @@
|
|||
/**
|
||||
* @provides javelin-router
|
||||
* @requires javelin-install
|
||||
* javelin-util
|
||||
* @javelin
|
||||
*/
|
||||
|
||||
/**
|
||||
* Route requests. Primarily, this class provides a quality-of-service
|
||||
* priority queue so large numbers of background loading tasks don't block
|
||||
* interactive requests.
|
||||
*/
|
||||
JX.install('Router', {
|
||||
|
||||
construct: function() {
|
||||
this._queue = [];
|
||||
},
|
||||
|
||||
events: ['queue', 'start', 'done'],
|
||||
|
||||
members: {
|
||||
_queue: null,
|
||||
_active: 0,
|
||||
_limit: 5,
|
||||
|
||||
queue: function(routable) {
|
||||
this._queue.push(routable);
|
||||
|
||||
this.invoke('queue', routable);
|
||||
this._update();
|
||||
},
|
||||
|
||||
getRoutableByKey: function(key) {
|
||||
for (var ii = 0; ii < this._queue.length; ii++) {
|
||||
if (this._queue[ii].getKey() == key) {
|
||||
return this._queue[ii];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Start new requests if we have slots free for them.
|
||||
*/
|
||||
_update: function() {
|
||||
var active = this._active;
|
||||
var limit = this._limit;
|
||||
|
||||
if (active >= limit) {
|
||||
// If we're already at the request limit, we can't add any more
|
||||
// requests.
|
||||
return;
|
||||
}
|
||||
|
||||
// If we only have one free slot, we reserve it for a request with
|
||||
// at least priority 1000.
|
||||
var minimum;
|
||||
if ((active + 1) == limit) {
|
||||
minimum = 1000;
|
||||
} else {
|
||||
minimum = 0;
|
||||
}
|
||||
|
||||
var idx = this._getNextRoutable(minimum);
|
||||
if (idx === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
var routable = this._queue[idx];
|
||||
this._queue.splice(idx, 1);
|
||||
|
||||
|
||||
routable.listen('done', JX.bind(this, this._done, routable));
|
||||
|
||||
this._active++;
|
||||
routable.start();
|
||||
this.invoke('start', routable);
|
||||
|
||||
this._update();
|
||||
},
|
||||
|
||||
_done: function(routable) {
|
||||
this._active--;
|
||||
this.invoke('done', routable);
|
||||
|
||||
this._update();
|
||||
},
|
||||
|
||||
_getNextRoutable: function(minimum) {
|
||||
var best = (minimum - 1);
|
||||
|
||||
var routable = null;
|
||||
for (var ii = 0; ii < this._queue.length; ii++) {
|
||||
var priority = this._queue[ii].getPriority();
|
||||
if (priority > best) {
|
||||
best = priority;
|
||||
routable = ii;
|
||||
}
|
||||
}
|
||||
|
||||
return routable;
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
statics: {
|
||||
_instance: null,
|
||||
getInstance: function() {
|
||||
if (!JX.Router._instance) {
|
||||
JX.Router._instance = new JX.Router();
|
||||
}
|
||||
return JX.Router._instance;
|
||||
}
|
||||
}
|
||||
});
|
13
webroot/rsrc/externals/javelin/lib/Workflow.js
vendored
13
webroot/rsrc/externals/javelin/lib/Workflow.js
vendored
|
@ -7,6 +7,7 @@
|
|||
* javelin-util
|
||||
* javelin-mask
|
||||
* javelin-uri
|
||||
* javelin-routable
|
||||
* @provides javelin-workflow
|
||||
* @javelin
|
||||
*/
|
||||
|
@ -259,6 +260,18 @@ JX.install('Workflow', {
|
|||
r.send();
|
||||
},
|
||||
|
||||
getRoutable: function() {
|
||||
var routable = new JX.Routable();
|
||||
routable.listen('start', JX.bind(this, function() {
|
||||
// Pass the event to allow other listeners to "start" to configure this
|
||||
// workflow before it fires.
|
||||
JX.Stratcom.pass(JX.Stratcom.context());
|
||||
this.start();
|
||||
}));
|
||||
this.listen('finally', JX.bind(routable, routable.done));
|
||||
return routable;
|
||||
},
|
||||
|
||||
setData : function(dictionary) {
|
||||
this._data = [];
|
||||
for (var k in dictionary) {
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
* javelin-uri
|
||||
* javelin-dom
|
||||
* javelin-json
|
||||
* javelin-router
|
||||
* phabricator-notification
|
||||
*/
|
||||
|
||||
|
@ -24,9 +25,15 @@ JX.behavior('aphlict-listen', function(config) {
|
|||
// a request to Phabricator to get notification details.
|
||||
function onaphlictmessage(type, message) {
|
||||
if (type == 'receive') {
|
||||
var request = new JX.Request('/notification/individual/', onnotification)
|
||||
var routable = new JX.Request('/notification/individual/', onnotification)
|
||||
.addData({key: message.key})
|
||||
.send();
|
||||
.getRoutable();
|
||||
|
||||
routable
|
||||
.setType('notification')
|
||||
.setPriority(250);
|
||||
|
||||
JX.Router.getInstance().queue(routable);
|
||||
} else if (__DEV__) {
|
||||
if (config.debug) {
|
||||
var details = message ? JX.JSON.stringify(message) : '';
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
* javelin-stratcom
|
||||
* javelin-behavior-device
|
||||
* javelin-vector
|
||||
* javelin-router
|
||||
* phabricator-tooltip
|
||||
*/
|
||||
|
||||
|
@ -74,6 +75,25 @@ JX.behavior('differential-populate', function(config) {
|
|||
// TODO: Once 1up works better, figure out when to show it.
|
||||
renderer = '2up';
|
||||
|
||||
var get_key = function(id) {
|
||||
return 'differential-populate.' + id;
|
||||
};
|
||||
|
||||
var load = function(id, data) {
|
||||
var routable = new JX.Workflow(config.uri, data)
|
||||
.setHandler(JX.bind(null, onresponse, id))
|
||||
.getRoutable();
|
||||
|
||||
routable
|
||||
.setPriority(500)
|
||||
.setType('content')
|
||||
.setKey(get_key(id));
|
||||
|
||||
JX.Router.getInstance().queue(routable);
|
||||
|
||||
return routable;
|
||||
};
|
||||
|
||||
for (var k in config.registry) {
|
||||
var data = {
|
||||
ref : config.registry[k],
|
||||
|
@ -81,9 +101,7 @@ JX.behavior('differential-populate', function(config) {
|
|||
renderer: renderer
|
||||
};
|
||||
|
||||
new JX.Workflow(config.uri, data)
|
||||
.setHandler(JX.bind(null, onresponse, k))
|
||||
.start();
|
||||
load(k, data);
|
||||
}
|
||||
|
||||
var highlighted = null;
|
||||
|
@ -104,13 +122,24 @@ JX.behavior('differential-populate', function(config) {
|
|||
JX.DOM.setContent(
|
||||
diff,
|
||||
JX.$H('<div class="differential-loading">Loading...</div>'));
|
||||
var data = {
|
||||
ref : meta.ref,
|
||||
whitespace : config.whitespace
|
||||
};
|
||||
new JX.Workflow(config.uri, data)
|
||||
.setHandler(JX.bind(null, onresponse, meta.id))
|
||||
.start();
|
||||
|
||||
// When a user explicitly clicks "Load" (or clicks a link in the table
|
||||
// of contents) prioritize this request if it already exists. If it
|
||||
// doesn't, make a new high-priority request.
|
||||
|
||||
var key = get_key(meta.id);
|
||||
var routable = JX.Router.getInstance().getRoutableByKey(key);
|
||||
|
||||
if (!routable) {
|
||||
var data = {
|
||||
ref : meta.ref,
|
||||
whitespace : config.whitespace
|
||||
};
|
||||
|
||||
routable = load(meta.id, data);
|
||||
}
|
||||
|
||||
routable.setPriority(2000);
|
||||
}
|
||||
if (meta.kill) {
|
||||
e.kill();
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
* @requires javelin-install
|
||||
* javelin-util
|
||||
* javelin-request
|
||||
* javelin-router
|
||||
* @provides phabricator-shaped-request
|
||||
* @javelin
|
||||
*/
|
||||
|
@ -63,7 +64,14 @@ JX.install('PhabricatorShapedRequest', {
|
|||
}));
|
||||
this._request.setData(data);
|
||||
this._request.setTimeout(this.getRequestTimeout());
|
||||
this._request.send();
|
||||
|
||||
var routable = this._request.getRoutable();
|
||||
|
||||
routable
|
||||
.setType('draft')
|
||||
.setPriority(750);
|
||||
|
||||
JX.Router.getInstance().queue(routable);
|
||||
} else {
|
||||
this._defer = setTimeout(
|
||||
JX.bind(this, this.trigger),
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
* @requires javelin-request
|
||||
* javelin-behavior
|
||||
* javelin-dom
|
||||
* javelin-router
|
||||
* javelin-util
|
||||
* phabricator-busy
|
||||
*/
|
||||
|
||||
|
@ -49,11 +51,97 @@ JX.behavior('refresh-csrf', function(config) {
|
|||
// Additionally, add the CSRF token as an HTTP header to every AJAX request.
|
||||
JX.Request.listen('open', function(r) {
|
||||
r.getTransport().setRequestHeader(config.header, current_token);
|
||||
JX.Busy.start();
|
||||
});
|
||||
|
||||
JX.Request.listen('finally', function(r) {
|
||||
JX.Busy.done();
|
||||
// Does this type of routable show the "Busy" spinner?
|
||||
var is_busy_type = function(type) {
|
||||
switch (type) {
|
||||
case 'workflow':
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
// Does this type of routable show the "Loading" bar?
|
||||
var is_bar_type = function(type) {
|
||||
switch (type) {
|
||||
case 'content':
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
var queue = {};
|
||||
var count = 0;
|
||||
var node;
|
||||
|
||||
// Redraw the loading bar.
|
||||
var redraw_bar = function() {
|
||||
// If all requests have completed, hide the bar after a moment.
|
||||
if (!count) {
|
||||
if (node) {
|
||||
node.firstChild.style.width = '100%';
|
||||
setTimeout(JX.bind(null, JX.DOM.remove, node), 500);
|
||||
}
|
||||
node = null;
|
||||
queue = {};
|
||||
return;
|
||||
}
|
||||
|
||||
// If we don't have the bar yet, draw it.
|
||||
if (!node) {
|
||||
node = JX.$N('div', {className: 'routing-bar'});
|
||||
document.body.appendChild(node);
|
||||
node.appendChild(JX.$N('div', {className: 'routing-progress'}));
|
||||
}
|
||||
|
||||
// Update the bar progress.
|
||||
var done = 0;
|
||||
var total = 0;
|
||||
for (var k in queue) {
|
||||
total++;
|
||||
if (queue[k]) {
|
||||
done++;
|
||||
}
|
||||
}
|
||||
|
||||
node.firstChild.style.width = (100 * (done / total)) + '%';
|
||||
};
|
||||
|
||||
|
||||
// Listen for queued requests.
|
||||
JX.Router.listen('queue', function(r) {
|
||||
var type = r.getType();
|
||||
|
||||
if (is_bar_type(type)) {
|
||||
queue[r.getID()] = false;
|
||||
count++;
|
||||
redraw_bar();
|
||||
}
|
||||
|
||||
if (is_busy_type(r.getType())) {
|
||||
JX.Busy.start();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Listen for completed requests.
|
||||
JX.Router.listen('done', function(r) {
|
||||
var type = r.getType();
|
||||
|
||||
if (is_bar_type(type)) {
|
||||
queue[r.getID()] = true;
|
||||
count--;
|
||||
redraw_bar();
|
||||
}
|
||||
|
||||
if (is_busy_type(r.getType())) {
|
||||
JX.Busy.done();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
|
|
@ -4,10 +4,21 @@
|
|||
* javelin-stratcom
|
||||
* javelin-workflow
|
||||
* javelin-dom
|
||||
* javelin-router
|
||||
*/
|
||||
|
||||
JX.behavior('workflow', function() {
|
||||
|
||||
// Queue a workflow at elevated priority. The user just clicked or submitted
|
||||
// something, so service this before loading background content.
|
||||
var queue = function(workflow) {
|
||||
var routable = workflow.getRoutable()
|
||||
.setPriority(2000)
|
||||
.setType('workflow');
|
||||
|
||||
JX.Router.getInstance().queue(routable);
|
||||
};
|
||||
|
||||
// If a user clicks an alternate submit button, make sure it gets marshalled
|
||||
// into the workflow.
|
||||
JX.Stratcom.listen(
|
||||
|
@ -40,7 +51,8 @@ JX.behavior('workflow', function() {
|
|||
// not just the <form /> itself.
|
||||
|
||||
e.prevent();
|
||||
JX.Workflow.newFromForm(e.getNode('tag:form'), extra).start();
|
||||
|
||||
queue(JX.Workflow.newFromForm(e.getNode('tag:form'), extra));
|
||||
});
|
||||
|
||||
JX.Stratcom.listen(
|
||||
|
@ -70,7 +82,7 @@ JX.behavior('workflow', function() {
|
|||
}
|
||||
|
||||
e.prevent();
|
||||
JX.Workflow.newFromLink(e.getNode('tag:a')).start();
|
||||
queue(JX.Workflow.newFromLink(e.getNode('tag:a')));
|
||||
});
|
||||
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue