mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-26 08:42:41 +01:00
Use standard UI elements to render pull requests in Releeph
Summary: Ref T3718. Ref T3644. Ref T3092. Switches from the Releeph UI elements to standard ones. I'll attach some screenshots. Also fixes CSRF against the request action endpoint. Test Plan: - Viewed request details. - Took actions on a request from detail page. - Viewed request list. - Took actions on a request from list page. - Used keyboard shortcuts to navigate list. - Used keyboard shortcuts to take actions. - Simulated errors. - Viewed on devices. Reviewers: chad, btrahan Reviewed By: btrahan Subscribers: grp, FacebookPOC, mattlqx, tala, beng, LegNeato, epriestley Maniphest Tasks: T3718, T3092, T3644 Differential Revision: https://secure.phabricator.com/D8771
This commit is contained in:
parent
41ea90c686
commit
35df988036
37 changed files with 573 additions and 1468 deletions
|
@ -18,7 +18,6 @@ return array(
|
|||
'maniphest.pkg.css' => 'f1887d71',
|
||||
'maniphest.pkg.js' => '2fe8af22',
|
||||
'rsrc/css/aphront/aphront-bars.css' => '231ac33c',
|
||||
'rsrc/css/aphront/aphront-notes.css' => '6acadd3f',
|
||||
'rsrc/css/aphront/context-bar.css' => '1c3b0529',
|
||||
'rsrc/css/aphront/dark-console.css' => '6378ef3d',
|
||||
'rsrc/css/aphront/dialog-view.css' => 'c01d24b4',
|
||||
|
@ -95,15 +94,10 @@ return array(
|
|||
'rsrc/css/application/ponder/vote.css' => '8ed6ed8b',
|
||||
'rsrc/css/application/profile/profile-view.css' => '33e6f703',
|
||||
'rsrc/css/application/projects/project-tag.css' => '095c9404',
|
||||
'rsrc/css/application/releeph/releeph-branch.css' => 'b8821d2d',
|
||||
'rsrc/css/application/releeph/releeph-colors.css' => '2d2d6aa8',
|
||||
'rsrc/css/application/releeph/releeph-core.css' => '140b959d',
|
||||
'rsrc/css/application/releeph/releeph-intents.css' => '39065521',
|
||||
'rsrc/css/application/releeph/releeph-core.css' => '9b3c5733',
|
||||
'rsrc/css/application/releeph/releeph-preview-branch.css' => 'b7a6f4a5',
|
||||
'rsrc/css/application/releeph/releeph-project.css' => 'ee1f9f57',
|
||||
'rsrc/css/application/releeph/releeph-request-differential-create-dialog.css' => '8d8b92cd',
|
||||
'rsrc/css/application/releeph/releeph-request-typeahead.css' => '667a48ae',
|
||||
'rsrc/css/application/releeph/releeph-status.css' => 'd119a005',
|
||||
'rsrc/css/application/search/search-results.css' => 'f240504c',
|
||||
'rsrc/css/application/settings/settings.css' => 'ea8f5915',
|
||||
'rsrc/css/application/slowvote/slowvote.css' => '266df6a1',
|
||||
|
@ -128,7 +122,7 @@ return array(
|
|||
'rsrc/css/phui/calendar/phui-calendar-list.css' => 'c1d0ca59',
|
||||
'rsrc/css/phui/calendar/phui-calendar-month.css' => 'a92e47d2',
|
||||
'rsrc/css/phui/calendar/phui-calendar.css' => '5e1ad989',
|
||||
'rsrc/css/phui/phui-box.css' => 'a36cf3a5',
|
||||
'rsrc/css/phui/phui-box.css' => '7b3a2eed',
|
||||
'rsrc/css/phui/phui-button.css' => '653ac588',
|
||||
'rsrc/css/phui/phui-document.css' => '3b078dc0',
|
||||
'rsrc/css/phui/phui-feed-story.css' => '3a59c2cf',
|
||||
|
@ -410,7 +404,7 @@ return array(
|
|||
'rsrc/js/application/projects/behavior-project-boards.js' => 'd8e135db',
|
||||
'rsrc/js/application/projects/behavior-project-create.js' => '065227cc',
|
||||
'rsrc/js/application/releeph/releeph-preview-branch.js' => '9eb2cedb',
|
||||
'rsrc/js/application/releeph/releeph-request-state-change.js' => 'fe7fc914',
|
||||
'rsrc/js/application/releeph/releeph-request-state-change.js' => 'd259e7c9',
|
||||
'rsrc/js/application/releeph/releeph-request-typeahead.js' => 'cd9e7094',
|
||||
'rsrc/js/application/repository/repository-crossreference.js' => '8ab282be',
|
||||
'rsrc/js/application/search/behavior-reorder-queries.js' => '37871df4',
|
||||
|
@ -493,7 +487,6 @@ return array(
|
|||
'aphront-error-view-css' => '9f1d5518',
|
||||
'aphront-list-filter-view-css' => 'ef989c67',
|
||||
'aphront-multi-column-view-css' => '12f65921',
|
||||
'aphront-notes' => '6acadd3f',
|
||||
'aphront-pager-view-css' => '2e3539af',
|
||||
'aphront-panel-view-css' => '5846dfa2',
|
||||
'aphront-request-failure-view-css' => 'da14df31',
|
||||
|
@ -621,7 +614,7 @@ return array(
|
|||
'javelin-behavior-project-create' => '065227cc',
|
||||
'javelin-behavior-refresh-csrf' => 'c4b31646',
|
||||
'javelin-behavior-releeph-preview-branch' => '9eb2cedb',
|
||||
'javelin-behavior-releeph-request-state-change' => 'fe7fc914',
|
||||
'javelin-behavior-releeph-request-state-change' => 'd259e7c9',
|
||||
'javelin-behavior-releeph-request-typeahead' => 'cd9e7094',
|
||||
'javelin-behavior-remarkup-preview' => 'f7379f45',
|
||||
'javelin-behavior-repository-crossreference' => '8ab282be',
|
||||
|
@ -743,7 +736,7 @@ return array(
|
|||
'phortune-credit-card-form-css' => 'b25b4beb',
|
||||
'phrequent-css' => 'ffc185ad',
|
||||
'phriction-document-css' => '7d7f0071',
|
||||
'phui-box-css' => 'a36cf3a5',
|
||||
'phui-box-css' => '7b3a2eed',
|
||||
'phui-button-css' => '653ac588',
|
||||
'phui-calendar-css' => '5e1ad989',
|
||||
'phui-calendar-day-css' => 'de035c8a',
|
||||
|
@ -779,15 +772,10 @@ return array(
|
|||
'raphael-core' => '51ee6b43',
|
||||
'raphael-g' => '40dde778',
|
||||
'raphael-g-line' => '40da039e',
|
||||
'releeph-branch' => 'b8821d2d',
|
||||
'releeph-colors' => '2d2d6aa8',
|
||||
'releeph-core' => '140b959d',
|
||||
'releeph-intents' => '39065521',
|
||||
'releeph-core' => '9b3c5733',
|
||||
'releeph-preview-branch' => 'b7a6f4a5',
|
||||
'releeph-project' => 'ee1f9f57',
|
||||
'releeph-request-differential-create-dialog' => '8d8b92cd',
|
||||
'releeph-request-typeahead-css' => '667a48ae',
|
||||
'releeph-status' => 'd119a005',
|
||||
'setup-issue-css' => '69e640e7',
|
||||
'sprite-actions-css' => '969ad0e5',
|
||||
'sprite-apps-css' => '6973a52b',
|
||||
|
@ -1727,6 +1715,15 @@ return array(
|
|||
array(
|
||||
0 => 'javelin-util',
|
||||
),
|
||||
'd259e7c9' =>
|
||||
array(
|
||||
0 => 'javelin-behavior',
|
||||
1 => 'javelin-dom',
|
||||
2 => 'javelin-stratcom',
|
||||
3 => 'javelin-workflow',
|
||||
4 => 'javelin-util',
|
||||
5 => 'phabricator-keyboard-shortcut',
|
||||
),
|
||||
'd4a14807' =>
|
||||
array(
|
||||
0 => 'javelin-install',
|
||||
|
@ -1950,15 +1947,6 @@ return array(
|
|||
4 => 'javelin-dom',
|
||||
5 => 'javelin-magical-init',
|
||||
),
|
||||
'fe7fc914' =>
|
||||
array(
|
||||
0 => 'javelin-behavior',
|
||||
1 => 'javelin-dom',
|
||||
2 => 'javelin-stratcom',
|
||||
3 => 'javelin-request',
|
||||
4 => 'phabricator-keyboard-shortcut',
|
||||
5 => 'phabricator-notification',
|
||||
),
|
||||
'fe80fb6d' =>
|
||||
array(
|
||||
0 => 'javelin-behavior',
|
||||
|
|
|
@ -65,7 +65,6 @@ phutil_register_library_map(array(
|
|||
'AphrontMoreView' => 'view/layout/AphrontMoreView.php',
|
||||
'AphrontMultiColumnView' => 'view/layout/AphrontMultiColumnView.php',
|
||||
'AphrontMySQLDatabaseConnectionTestCase' => 'infrastructure/storage/__tests__/AphrontMySQLDatabaseConnectionTestCase.php',
|
||||
'AphrontNoteView' => 'view/widget/AphrontNoteView.php',
|
||||
'AphrontNullView' => 'view/AphrontNullView.php',
|
||||
'AphrontPHPHTTPSink' => 'aphront/sink/AphrontPHPHTTPSink.php',
|
||||
'AphrontPageView' => 'view/page/AphrontPageView.php',
|
||||
|
@ -1716,7 +1715,6 @@ phutil_register_library_map(array(
|
|||
'PhabricatorMySQLFileStorageEngine' => 'applications/files/engine/PhabricatorMySQLFileStorageEngine.php',
|
||||
'PhabricatorNamedQuery' => 'applications/search/storage/PhabricatorNamedQuery.php',
|
||||
'PhabricatorNamedQueryQuery' => 'applications/search/query/PhabricatorNamedQueryQuery.php',
|
||||
'PhabricatorNoteExample' => 'applications/uiexample/examples/PhabricatorNoteExample.php',
|
||||
'PhabricatorNotificationAdHocFeedStory' => 'applications/notification/feed/PhabricatorNotificationAdHocFeedStory.php',
|
||||
'PhabricatorNotificationBuilder' => 'applications/notification/builder/PhabricatorNotificationBuilder.php',
|
||||
'PhabricatorNotificationClearController' => 'applications/notification/controller/PhabricatorNotificationClearController.php',
|
||||
|
@ -2555,26 +2553,22 @@ phutil_register_library_map(array(
|
|||
'ReleephRequestController' => 'applications/releeph/controller/request/ReleephRequestController.php',
|
||||
'ReleephRequestDifferentialCreateController' => 'applications/releeph/controller/request/ReleephRequestDifferentialCreateController.php',
|
||||
'ReleephRequestEditController' => 'applications/releeph/controller/request/ReleephRequestEditController.php',
|
||||
'ReleephRequestHeaderListView' => 'applications/releeph/view/request/header/ReleephRequestHeaderListView.php',
|
||||
'ReleephRequestHeaderView' => 'applications/releeph/view/request/header/ReleephRequestHeaderView.php',
|
||||
'ReleephRequestIntentsView' => 'applications/releeph/view/request/ReleephRequestIntentsView.php',
|
||||
'ReleephRequestMailReceiver' => 'applications/releeph/mail/ReleephRequestMailReceiver.php',
|
||||
'ReleephRequestQuery' => 'applications/releeph/query/ReleephRequestQuery.php',
|
||||
'ReleephRequestReplyHandler' => 'applications/releeph/mail/ReleephRequestReplyHandler.php',
|
||||
'ReleephRequestSearchEngine' => 'applications/releeph/query/ReleephRequestSearchEngine.php',
|
||||
'ReleephRequestStatus' => 'applications/releeph/constants/ReleephRequestStatus.php',
|
||||
'ReleephRequestStatusView' => 'applications/releeph/view/request/ReleephRequestStatusView.php',
|
||||
'ReleephRequestTransaction' => 'applications/releeph/storage/ReleephRequestTransaction.php',
|
||||
'ReleephRequestTransactionComment' => 'applications/releeph/storage/ReleephRequestTransactionComment.php',
|
||||
'ReleephRequestTransactionQuery' => 'applications/releeph/query/ReleephRequestTransactionQuery.php',
|
||||
'ReleephRequestTransactionalEditor' => 'applications/releeph/editor/ReleephRequestTransactionalEditor.php',
|
||||
'ReleephRequestTypeaheadControl' => 'applications/releeph/view/request/ReleephRequestTypeaheadControl.php',
|
||||
'ReleephRequestTypeaheadController' => 'applications/releeph/controller/request/ReleephRequestTypeaheadController.php',
|
||||
'ReleephRequestView' => 'applications/releeph/view/ReleephRequestView.php',
|
||||
'ReleephRequestViewController' => 'applications/releeph/controller/request/ReleephRequestViewController.php',
|
||||
'ReleephRequestorFieldSpecification' => 'applications/releeph/field/specification/ReleephRequestorFieldSpecification.php',
|
||||
'ReleephRevisionFieldSpecification' => 'applications/releeph/field/specification/ReleephRevisionFieldSpecification.php',
|
||||
'ReleephSeverityFieldSpecification' => 'applications/releeph/field/specification/ReleephSeverityFieldSpecification.php',
|
||||
'ReleephStatusFieldSpecification' => 'applications/releeph/field/specification/ReleephStatusFieldSpecification.php',
|
||||
'ReleephSummaryFieldSpecification' => 'applications/releeph/field/specification/ReleephSummaryFieldSpecification.php',
|
||||
'ShellLogView' => 'applications/harbormaster/view/ShellLogView.php',
|
||||
'SlowvoteEmbedView' => 'applications/slowvote/view/SlowvoteEmbedView.php',
|
||||
|
@ -2662,7 +2656,6 @@ phutil_register_library_map(array(
|
|||
'AphrontMoreView' => 'AphrontView',
|
||||
'AphrontMultiColumnView' => 'AphrontView',
|
||||
'AphrontMySQLDatabaseConnectionTestCase' => 'PhabricatorTestCase',
|
||||
'AphrontNoteView' => 'AphrontView',
|
||||
'AphrontNullView' => 'AphrontView',
|
||||
'AphrontPHPHTTPSink' => 'AphrontHTTPSink',
|
||||
'AphrontPageView' => 'AphrontView',
|
||||
|
@ -4531,7 +4524,6 @@ phutil_register_library_map(array(
|
|||
1 => 'PhabricatorPolicyInterface',
|
||||
),
|
||||
'PhabricatorNamedQueryQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||
'PhabricatorNoteExample' => 'PhabricatorUIExample',
|
||||
'PhabricatorNotificationAdHocFeedStory' => 'PhabricatorFeedStory',
|
||||
'PhabricatorNotificationClearController' => 'PhabricatorNotificationController',
|
||||
'PhabricatorNotificationConfigOptions' => 'PhabricatorApplicationConfigOptions',
|
||||
|
@ -5574,25 +5566,21 @@ phutil_register_library_map(array(
|
|||
'ReleephRequestController' => 'ReleephController',
|
||||
'ReleephRequestDifferentialCreateController' => 'ReleephController',
|
||||
'ReleephRequestEditController' => 'ReleephBranchController',
|
||||
'ReleephRequestHeaderListView' => 'AphrontView',
|
||||
'ReleephRequestHeaderView' => 'AphrontView',
|
||||
'ReleephRequestIntentsView' => 'AphrontView',
|
||||
'ReleephRequestMailReceiver' => 'PhabricatorObjectMailReceiver',
|
||||
'ReleephRequestQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||
'ReleephRequestReplyHandler' => 'PhabricatorMailReplyHandler',
|
||||
'ReleephRequestSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
||||
'ReleephRequestStatusView' => 'AphrontView',
|
||||
'ReleephRequestTransaction' => 'PhabricatorApplicationTransaction',
|
||||
'ReleephRequestTransactionComment' => 'PhabricatorApplicationTransactionComment',
|
||||
'ReleephRequestTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
||||
'ReleephRequestTransactionalEditor' => 'PhabricatorApplicationTransactionEditor',
|
||||
'ReleephRequestTypeaheadControl' => 'AphrontFormControl',
|
||||
'ReleephRequestTypeaheadController' => 'PhabricatorTypeaheadDatasourceController',
|
||||
'ReleephRequestView' => 'AphrontView',
|
||||
'ReleephRequestViewController' => 'ReleephBranchController',
|
||||
'ReleephRequestorFieldSpecification' => 'ReleephFieldSpecification',
|
||||
'ReleephRevisionFieldSpecification' => 'ReleephFieldSpecification',
|
||||
'ReleephSeverityFieldSpecification' => 'ReleephLevelFieldSpecification',
|
||||
'ReleephStatusFieldSpecification' => 'ReleephFieldSpecification',
|
||||
'ReleephSummaryFieldSpecification' => 'ReleephFieldSpecification',
|
||||
'ShellLogView' => 'AphrontView',
|
||||
'SlowvoteEmbedView' => 'AphrontView',
|
||||
|
|
|
@ -14,20 +14,19 @@ final class PhabricatorApplicationReleephConfigOptions
|
|||
public function getOptions() {
|
||||
|
||||
$default_fields = array(
|
||||
new ReleephCommitMessageFieldSpecification(),
|
||||
new ReleephSummaryFieldSpecification(),
|
||||
new ReleephRequestorFieldSpecification(),
|
||||
new ReleephSeverityFieldSpecification(),
|
||||
new ReleephIntentFieldSpecification(),
|
||||
new ReleephReasonFieldSpecification(),
|
||||
new ReleephAuthorFieldSpecification(),
|
||||
new ReleephRevisionFieldSpecification(),
|
||||
new ReleephRequestorFieldSpecification(),
|
||||
new ReleephSeverityFieldSpecification(),
|
||||
new ReleephOriginalCommitFieldSpecification(),
|
||||
new ReleephDiffMessageFieldSpecification(),
|
||||
new ReleephStatusFieldSpecification(),
|
||||
new ReleephIntentFieldSpecification(),
|
||||
new ReleephBranchCommitFieldSpecification(),
|
||||
new ReleephDiffSizeFieldSpecification(),
|
||||
new ReleephDiffChurnFieldSpecification(),
|
||||
new ReleephDiffMessageFieldSpecification(),
|
||||
new ReleephCommitMessageFieldSpecification(),
|
||||
);
|
||||
|
||||
$default = array();
|
||||
|
|
|
@ -15,9 +15,9 @@ final class ReleephRequestStatus {
|
|||
self::STATUS_REQUESTED => pht('Requested'),
|
||||
self::STATUS_REJECTED => pht('Rejected'),
|
||||
self::STATUS_ABANDONED => pht('Abandoned'),
|
||||
self::STATUS_PICKED => pht('Picked'),
|
||||
self::STATUS_PICKED => pht('Pulled'),
|
||||
self::STATUS_REVERTED => pht('Reverted'),
|
||||
self::STATUS_NEEDS_PICK => pht('Needs Pick'),
|
||||
self::STATUS_NEEDS_PICK => pht('Needs Pull'),
|
||||
self::STATUS_NEEDS_REVERT => pht('Needs Revert'),
|
||||
);
|
||||
return idx($descriptions, $status, '??');
|
||||
|
|
|
@ -44,19 +44,40 @@ final class ReleephBranchViewController extends ReleephBranchController
|
|||
assert_instances_of($requests, 'ReleephRequest');
|
||||
$viewer = $this->getRequest()->getUser();
|
||||
|
||||
$branch = $this->getBranch();
|
||||
// TODO: This is generally a bit sketchy, but we don't do this kind of
|
||||
// thing elsewhere at the moment. For the moment it shouldn't be hugely
|
||||
// costly, and we can batch things later. Generally, this commits fewer
|
||||
// sins than the old code did.
|
||||
|
||||
// TODO: Really really gross.
|
||||
$branch->populateReleephRequestHandles(
|
||||
$viewer,
|
||||
$requests);
|
||||
$engine = id(new PhabricatorMarkupEngine())
|
||||
->setViewer($viewer);
|
||||
|
||||
$list = id(new ReleephRequestHeaderListView())
|
||||
->setUser($viewer)
|
||||
->setAphrontRequest($this->getRequest())
|
||||
->setReleephProject($branch->getProduct())
|
||||
->setReleephBranch($branch)
|
||||
->setReleephRequests($requests);
|
||||
$list = array();
|
||||
foreach ($requests as $pull) {
|
||||
$field_list = PhabricatorCustomField::getObjectFields(
|
||||
$pull,
|
||||
PhabricatorCustomField::ROLE_VIEW);
|
||||
|
||||
$field_list
|
||||
->setViewer($viewer)
|
||||
->readFieldsFromStorage($pull);
|
||||
|
||||
foreach ($field_list->getFields() as $field) {
|
||||
if ($field->shouldMarkup()) {
|
||||
$field->setMarkupEngine($engine);
|
||||
}
|
||||
}
|
||||
|
||||
$list[] = id(new ReleephRequestView())
|
||||
->setUser($viewer)
|
||||
->setCustomFields($field_list)
|
||||
->setPullRequest($pull)
|
||||
->setIsListView(true);
|
||||
}
|
||||
|
||||
// This is quite sketchy, but the list has not actually rendered yet, so
|
||||
// this still allows us to batch the markup rendering.
|
||||
$engine->process();
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
|
|
@ -15,6 +15,8 @@ final class ReleephRequestActionController
|
|||
$request = $this->getRequest();
|
||||
$viewer = $request->getUser();
|
||||
|
||||
$request->validateCSRF();
|
||||
|
||||
$pull = id(new ReleephRequestQuery())
|
||||
->setViewer($viewer)
|
||||
->withIDs(array($this->requestID))
|
||||
|
@ -26,8 +28,6 @@ final class ReleephRequestActionController
|
|||
$branch = $pull->getBranch();
|
||||
$product = $branch->getProduct();
|
||||
|
||||
$branch->populateReleephRequestHandles($viewer, array($pull));
|
||||
|
||||
$action = $this->action;
|
||||
|
||||
$origin_uri = '/'.$pull->getMonogram();
|
||||
|
@ -93,22 +93,37 @@ final class ReleephRequestActionController
|
|||
|
||||
$editor->applyTransactions($pull, $xactions);
|
||||
|
||||
// If we're adding a new user to userIntents, we'll have to re-populate
|
||||
// request handles to load that user's data.
|
||||
//
|
||||
// This is cheap enough to do every time.
|
||||
$branch->populateReleephRequestHandles($viewer, array($pull));
|
||||
if ($request->getBool('render')) {
|
||||
$field_list = PhabricatorCustomField::getObjectFields(
|
||||
$pull,
|
||||
PhabricatorCustomField::ROLE_VIEW);
|
||||
|
||||
$list = id(new ReleephRequestHeaderListView())
|
||||
->setReleephProject($product)
|
||||
->setReleephBranch($branch)
|
||||
->setReleephRequests(array($pull))
|
||||
->setUser($viewer)
|
||||
->setAphrontRequest($request);
|
||||
$field_list
|
||||
->setViewer($viewer)
|
||||
->readFieldsFromStorage($pull);
|
||||
|
||||
return id(new AphrontAjaxResponse())->setContent(
|
||||
array(
|
||||
'markup' => hsprintf('%s', $list->renderInner()),
|
||||
));
|
||||
// TODO: This should be more modern and general.
|
||||
$engine = id(new PhabricatorMarkupEngine())
|
||||
->setViewer($viewer);
|
||||
foreach ($field_list->getFields() as $field) {
|
||||
if ($field->shouldMarkup()) {
|
||||
$field->setMarkupEngine($engine);
|
||||
}
|
||||
}
|
||||
$engine->process();
|
||||
|
||||
$pull_box = id(new ReleephRequestView())
|
||||
->setUser($viewer)
|
||||
->setCustomFields($field_list)
|
||||
->setPullRequest($pull)
|
||||
->setIsListView(true);
|
||||
|
||||
return id(new AphrontAjaxResponse())->setContent(
|
||||
array(
|
||||
'markup' => hsprintf('%s', $pull_box),
|
||||
));
|
||||
}
|
||||
|
||||
return id(new AphrontRedirectResponse())->setURI($origin_uri);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,21 +33,28 @@ final class ReleephRequestViewController
|
|||
// TODO: Break this 1:1 stuff?
|
||||
$branch = $pull->getBranch();
|
||||
|
||||
// TODO: Very gross.
|
||||
$branch->populateReleephRequestHandles(
|
||||
$viewer,
|
||||
array($pull));
|
||||
$field_list = PhabricatorCustomField::getObjectFields(
|
||||
$pull,
|
||||
PhabricatorCustomField::ROLE_VIEW);
|
||||
|
||||
$rq_view = id(new ReleephRequestHeaderListView())
|
||||
->setReleephProject($branch->getProduct())
|
||||
->setReleephBranch($branch)
|
||||
->setReleephRequests(array($pull))
|
||||
->setUser($viewer)
|
||||
->setAphrontRequest($request)
|
||||
->setReloadOnStateChange(true);
|
||||
$field_list
|
||||
->setViewer($viewer)
|
||||
->readFieldsFromStorage($pull);
|
||||
|
||||
// TODO: This should be more modern and general.
|
||||
$engine = id(new PhabricatorMarkupEngine())
|
||||
->setViewer($viewer);
|
||||
foreach ($field_list->getFields() as $field) {
|
||||
if ($field->shouldMarkup()) {
|
||||
$field->setMarkupEngine($engine);
|
||||
}
|
||||
}
|
||||
$engine->process();
|
||||
|
||||
$pull_box = id(new ReleephRequestView())
|
||||
->setUser($viewer)
|
||||
->setCustomFields($field_list)
|
||||
->setPullRequest($pull);
|
||||
|
||||
$xactions = id(new ReleephRequestTransactionQuery())
|
||||
->setViewer($viewer)
|
||||
|
@ -85,12 +92,15 @@ final class ReleephRequestViewController
|
|||
return $this->buildStandardPageResponse(
|
||||
array(
|
||||
$crumbs,
|
||||
$rq_view,
|
||||
$pull_box,
|
||||
$timeline,
|
||||
$add_comment_form,
|
||||
),
|
||||
array(
|
||||
'title' => $title
|
||||
'title' => $title,
|
||||
'device' => true,
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -37,7 +37,6 @@ final class ReleephDefaultFieldSelector extends ReleephFieldSelector {
|
|||
new ReleephFacebookSeverityFieldSpecification(),
|
||||
new ReleephOriginalCommitFieldSpecification(),
|
||||
new ReleephDiffMessageFieldSpecification(),
|
||||
new ReleephStatusFieldSpecification(),
|
||||
new ReleephIntentFieldSpecification(),
|
||||
new ReleephBranchCommitFieldSpecification(),
|
||||
new ReleephDiffSizeFieldSpecification(),
|
||||
|
@ -57,7 +56,6 @@ final class ReleephDefaultFieldSelector extends ReleephFieldSelector {
|
|||
new ReleephSeverityFieldSpecification(),
|
||||
new ReleephOriginalCommitFieldSpecification(),
|
||||
new ReleephDiffMessageFieldSpecification(),
|
||||
new ReleephStatusFieldSpecification(),
|
||||
new ReleephIntentFieldSpecification(),
|
||||
new ReleephBranchCommitFieldSpecification(),
|
||||
new ReleephDiffSizeFieldSpecification(),
|
||||
|
@ -66,91 +64,6 @@ final class ReleephDefaultFieldSelector extends ReleephFieldSelector {
|
|||
}
|
||||
}
|
||||
|
||||
public function arrangeFieldsForHeaderView(array $fields) {
|
||||
if (self::isFacebook()) {
|
||||
return array(
|
||||
// Top group
|
||||
array(
|
||||
'left' => self::selectFields($fields, array(
|
||||
'ReleephAuthorFieldSpecification',
|
||||
'ReleephRevisionFieldSpecification',
|
||||
'ReleephOriginalCommitFieldSpecification',
|
||||
'ReleephDiffSizeFieldSpecification',
|
||||
'ReleephDiffChurnFieldSpecification',
|
||||
'ReleephDependsOnFieldSpecification',
|
||||
'ReleephFacebookTasksFieldSpecification',
|
||||
)),
|
||||
'right' => self::selectFields($fields, array(
|
||||
'ReleephRequestorFieldSpecification',
|
||||
'ReleephFacebookKarmaFieldSpecification',
|
||||
'ReleephFacebookSeverityFieldSpecification',
|
||||
'ReleephFacebookTagFieldSpecification',
|
||||
'ReleephStatusFieldSpecification',
|
||||
'ReleephIntentFieldSpecification',
|
||||
'ReleephBranchCommitFieldSpecification',
|
||||
))
|
||||
),
|
||||
|
||||
// Bottom group
|
||||
array(
|
||||
'left' => self::selectFields($fields, array(
|
||||
'ReleephDiffMessageFieldSpecification',
|
||||
)),
|
||||
'right' => self::selectFields($fields, array(
|
||||
'ReleephReasonFieldSpecification',
|
||||
))
|
||||
)
|
||||
);
|
||||
} else {
|
||||
return array(
|
||||
// Top group
|
||||
array(
|
||||
'left' => self::selectFields($fields, array(
|
||||
'ReleephAuthorFieldSpecification',
|
||||
'ReleephRevisionFieldSpecification',
|
||||
'ReleephOriginalCommitFieldSpecification',
|
||||
'ReleephDiffSizeFieldSpecification',
|
||||
'ReleephDiffChurnFieldSpecification',
|
||||
)),
|
||||
'right' => self::selectFields($fields, array(
|
||||
'ReleephRequestorFieldSpecification',
|
||||
'ReleephSeverityFieldSpecification',
|
||||
'ReleephStatusFieldSpecification',
|
||||
'ReleephIntentFieldSpecification',
|
||||
'ReleephBranchCommitFieldSpecification',
|
||||
))
|
||||
),
|
||||
|
||||
// Bottom group
|
||||
array(
|
||||
'left' => self::selectFields($fields, array(
|
||||
'ReleephDiffMessageFieldSpecification',
|
||||
)),
|
||||
'right' => self::selectFields($fields, array(
|
||||
'ReleephReasonFieldSpecification',
|
||||
))
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function arrangeFieldsForSelectForm(array $fields) {
|
||||
if (self::isFacebook()) {
|
||||
return self::selectFields($fields, array(
|
||||
'ReleephStatusFieldSpecification',
|
||||
'ReleephFacebookSeverityFieldSpecification',
|
||||
'ReleephRequestorFieldSpecification',
|
||||
'ReleephFacebookTagFieldSpecification',
|
||||
));
|
||||
} else {
|
||||
return self::selectFields($fields, array(
|
||||
'ReleephStatusFieldSpecification',
|
||||
'ReleephSeverityFieldSpecification',
|
||||
'ReleephRequestorFieldSpecification',
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
public function sortFieldsForCommitMessage(array $fields) {
|
||||
return self::selectFields($fields, array(
|
||||
'ReleephCommitMessageFieldSpecification',
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Control the rendering of ReleephRequestHeaderView, and the layout of the
|
||||
* ReleephRequest search dialog (in ReleephBranchViewController.)
|
||||
*/
|
||||
abstract class ReleephFieldSelector {
|
||||
|
||||
final public function __construct() {
|
||||
|
@ -12,10 +8,6 @@ abstract class ReleephFieldSelector {
|
|||
|
||||
abstract public function getFieldSpecifications();
|
||||
|
||||
abstract public function arrangeFieldsForHeaderView(array $fields);
|
||||
|
||||
abstract public function arrangeFieldsForSelectForm(array $fields);
|
||||
|
||||
public function sortFieldsForCommitMessage(array $fields) {
|
||||
assert_instances_of($fields, 'ReleephFieldSpecification');
|
||||
return $fields;
|
||||
|
|
|
@ -24,17 +24,23 @@ final class ReleephAuthorFieldSpecification
|
|||
}
|
||||
|
||||
public function renderValueForHeaderView() {
|
||||
$rr = $this->getReleephRequest();
|
||||
$author_phid = idx(self::$authorMap, $rr->getPHID());
|
||||
if ($author_phid) {
|
||||
$handle = id(new PhabricatorHandleQuery())
|
||||
->setViewer($this->getUser())
|
||||
->withPHIDs(array($author_phid))
|
||||
->executeOne();
|
||||
return $handle->renderLink();
|
||||
} else {
|
||||
return 'Unknown Author';
|
||||
$pull = $this->getReleephRequest();
|
||||
$commit = $pull->loadPhabricatorRepositoryCommit();
|
||||
if (!$commit) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$author_phid = $commit->getAuthorPHID();
|
||||
if (!$author_phid) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$handle = id(new PhabricatorHandleQuery())
|
||||
->setViewer($this->getUser())
|
||||
->withPHIDs(array($author_phid))
|
||||
->executeOne();
|
||||
|
||||
return $handle->renderLink();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -11,6 +11,10 @@ final class ReleephCommitMessageFieldSpecification
|
|||
return '__only_for_commit_message!';
|
||||
}
|
||||
|
||||
public function shouldAppearInPropertyView() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public function shouldAppearOnCommitMessage() {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -15,18 +15,17 @@ final class ReleephDiffMessageFieldSpecification
|
|||
return null;
|
||||
}
|
||||
|
||||
public function getStyleForPropertyView() {
|
||||
return 'block';
|
||||
}
|
||||
|
||||
public function renderValueForHeaderView() {
|
||||
$markup = phutil_tag(
|
||||
return phutil_tag(
|
||||
'div',
|
||||
array(
|
||||
'class' => 'phabricator-remarkup',
|
||||
),
|
||||
$this->getMarkupEngineOutput());
|
||||
|
||||
return id(new AphrontNoteView())
|
||||
->setTitle('Commit Message')
|
||||
->appendChild($markup)
|
||||
->render();
|
||||
}
|
||||
|
||||
public function shouldMarkup() {
|
||||
|
|
|
@ -13,6 +13,30 @@ abstract class ReleephFieldSpecification
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function shouldAppearInPropertyView() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function renderPropertyViewLabel() {
|
||||
return $this->getName();
|
||||
}
|
||||
|
||||
public function renderPropertyViewValue(array $handles) {
|
||||
$value = $this->renderValueForHeaderView();
|
||||
if ($value === '') {
|
||||
return null;
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function slowlyLoadHandle($phid) {
|
||||
// TODO: Remove this, it's transitional as fields modernize.
|
||||
return id(new PhabricatorHandleQuery())
|
||||
->withPHIDs(array($phid))
|
||||
->setViewer($this->getUser())
|
||||
->executeOne();
|
||||
}
|
||||
|
||||
abstract public function getName();
|
||||
|
||||
/* -( Storage )------------------------------------------------------------ */
|
||||
|
@ -148,18 +172,30 @@ abstract class ReleephFieldSpecification
|
|||
}
|
||||
|
||||
final public function getReleephProject() {
|
||||
if (!$this->releephProject) {
|
||||
return $this->getReleephBranch()->getProduct();
|
||||
}
|
||||
return $this->releephProject;
|
||||
}
|
||||
|
||||
final public function getReleephBranch() {
|
||||
if (!$this->releephBranch) {
|
||||
return $this->getReleephRequest()->getBranch();
|
||||
}
|
||||
return $this->releephBranch;
|
||||
}
|
||||
|
||||
final public function getReleephRequest() {
|
||||
if (!$this->releephRequest) {
|
||||
return $this->getObject();
|
||||
}
|
||||
return $this->releephRequest;
|
||||
}
|
||||
|
||||
final public function getUser() {
|
||||
if (!$this->user) {
|
||||
return $this->getViewer();
|
||||
}
|
||||
return $this->user;
|
||||
}
|
||||
|
||||
|
|
|
@ -12,10 +12,67 @@ final class ReleephIntentFieldSpecification
|
|||
}
|
||||
|
||||
public function renderValueForHeaderView() {
|
||||
return id(new ReleephRequestIntentsView())
|
||||
->setReleephRequest($this->getReleephRequest())
|
||||
->setReleephProject($this->getReleephProject())
|
||||
->render();
|
||||
$pull = $this->getReleephRequest();
|
||||
|
||||
$intents = $pull->getUserIntents();
|
||||
$product = $this->getReleephProject();
|
||||
|
||||
if (!$intents) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$user_phids = array_keys($intents);
|
||||
if ($user_phids) {
|
||||
$handles = id(new PhabricatorHandleQuery())
|
||||
->withPHIDs($user_phids)
|
||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||
->execute();
|
||||
} else {
|
||||
$handles = array();
|
||||
}
|
||||
|
||||
$pushers = array();
|
||||
$others = array();
|
||||
|
||||
foreach ($intents as $phid => $intent) {
|
||||
if ($product->isAuthoritativePHID($phid)) {
|
||||
$pushers[$phid] = $intent;
|
||||
} else {
|
||||
$others[$phid] = $intent;
|
||||
}
|
||||
}
|
||||
|
||||
$intents = $pushers + $others;
|
||||
|
||||
$view = id(new PHUIStatusListView());
|
||||
foreach ($intents as $phid => $intent) {
|
||||
switch ($intent) {
|
||||
case ReleephRequest::INTENT_WANT:
|
||||
$icon = 'accept-green';
|
||||
$label = pht('Want');
|
||||
break;
|
||||
case ReleephRequest::INTENT_PASS:
|
||||
$icon = 'reject-red';
|
||||
$label = pht('Pass');
|
||||
break;
|
||||
default:
|
||||
$icon = 'question';
|
||||
$label = pht('Unknown Intent (%s)', $intent);
|
||||
break;
|
||||
}
|
||||
|
||||
$target = $handles[$phid]->renderLink();
|
||||
if ($product->isAuthoritativePHID($phid)) {
|
||||
$target = phutil_tag('strong', array(), $target);
|
||||
}
|
||||
|
||||
$view->addItem(
|
||||
id(new PHUIStatusItemView())
|
||||
->setIcon($icon, $label)
|
||||
->setTarget($target));
|
||||
}
|
||||
|
||||
return $view;
|
||||
}
|
||||
|
||||
public function shouldAppearOnCommitMessage() {
|
||||
|
|
|
@ -12,9 +12,8 @@ final class ReleephOriginalCommitFieldSpecification
|
|||
}
|
||||
|
||||
public function renderValueForHeaderView() {
|
||||
$rr = $this->getReleephRequest();
|
||||
$handles = $rr->getHandles();
|
||||
return $handles[$rr->getRequestCommitPHID()]->renderLink();
|
||||
$pull = $this->getReleephRequest();
|
||||
return $this->slowlyLoadHandle($pull->getRequestCommitPHID())->renderLink();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -15,22 +15,25 @@ final class ReleephReasonFieldSpecification
|
|||
return 'reason';
|
||||
}
|
||||
|
||||
public function getStyleForPropertyView() {
|
||||
return 'block';
|
||||
}
|
||||
|
||||
public function renderLabelForHeaderView() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getIconForPropertyView() {
|
||||
return PHUIPropertyListView::ICON_SUMMARY;
|
||||
}
|
||||
|
||||
public function renderValueForHeaderView() {
|
||||
$markup = phutil_tag(
|
||||
return phutil_tag(
|
||||
'div',
|
||||
array(
|
||||
'class' => 'phabricator-remarkup',
|
||||
),
|
||||
$this->getMarkupEngineOutput());
|
||||
|
||||
return id(new AphrontNoteView())
|
||||
->setTitle('Reason')
|
||||
->appendChild($markup)
|
||||
->render();
|
||||
}
|
||||
|
||||
private $error = true;
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class ReleephStatusFieldSpecification
|
||||
extends ReleephFieldSpecification {
|
||||
|
||||
public function getFieldKey() {
|
||||
return 'status';
|
||||
}
|
||||
|
||||
public function getName() {
|
||||
return 'Status';
|
||||
}
|
||||
|
||||
public function renderValueForHeaderView() {
|
||||
return id(new ReleephRequestStatusView())
|
||||
->setReleephRequest($this->getReleephRequest())
|
||||
->render();
|
||||
}
|
||||
|
||||
}
|
|
@ -5,6 +5,10 @@ final class ReleephSummaryFieldSpecification
|
|||
|
||||
const MAX_SUMMARY_LENGTH = 60;
|
||||
|
||||
public function shouldAppearInPropertyView() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getFieldKey() {
|
||||
return 'summary';
|
||||
}
|
||||
|
|
|
@ -187,38 +187,21 @@ final class ReleephRequest extends ReleephDAO
|
|||
return $reason;
|
||||
}
|
||||
|
||||
public function getSummary() {
|
||||
/**
|
||||
* Instead, you can use:
|
||||
* - getDetail('summary') // the actual user-chosen summary
|
||||
* - getSummaryForDisplay() // falls back to the original commit title
|
||||
*
|
||||
* Or for the fastidious:
|
||||
* - id(new ReleephSummaryFieldSpecification())
|
||||
* ->setReleephRequest($rr)
|
||||
* ->getValue() // programmatic equivalent to getDetail()
|
||||
*/
|
||||
throw new Exception(
|
||||
"getSummary() has been deprecated!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow a null summary, and fall back to the title of the commit.
|
||||
*/
|
||||
public function getSummaryForDisplay() {
|
||||
$summary = $this->getDetail('summary');
|
||||
|
||||
if (!$summary) {
|
||||
$pr_commit_data = $this->loadPhabricatorRepositoryCommitData();
|
||||
if ($pr_commit_data) {
|
||||
$message_lines = explode("\n", $pr_commit_data->getCommitMessage());
|
||||
$message_lines = array_filter($message_lines);
|
||||
$summary = head($message_lines);
|
||||
if (!strlen($summary)) {
|
||||
$commit = $this->loadPhabricatorRepositoryCommit();
|
||||
if ($commit) {
|
||||
$summary = $commit->getSummary();
|
||||
}
|
||||
}
|
||||
|
||||
if (!$summary) {
|
||||
$summary = '(no summary given and commit message empty or unparsed)';
|
||||
if (!strlen($summary)) {
|
||||
$summary = pht('None');
|
||||
}
|
||||
|
||||
return $summary;
|
||||
|
|
249
src/applications/releeph/view/ReleephRequestView.php
Normal file
249
src/applications/releeph/view/ReleephRequestView.php
Normal file
|
@ -0,0 +1,249 @@
|
|||
<?php
|
||||
|
||||
final class ReleephRequestView extends AphrontView {
|
||||
|
||||
private $pullRequest;
|
||||
private $customFields;
|
||||
private $isListView;
|
||||
|
||||
public function setIsListView($is_list_view) {
|
||||
$this->isListView = $is_list_view;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getIsListView() {
|
||||
return $this->isListView;
|
||||
}
|
||||
|
||||
public function setCustomFields(PhabricatorCustomFieldList $custom_fields) {
|
||||
$this->customFields = $custom_fields;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCustomFields() {
|
||||
return $this->customFields;
|
||||
}
|
||||
|
||||
public function setPullRequest(ReleephRequest $pull_request) {
|
||||
$this->pullRequest = $pull_request;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPullRequest() {
|
||||
return $this->pullRequest;
|
||||
}
|
||||
|
||||
public function render() {
|
||||
$viewer = $this->getUser();
|
||||
|
||||
$field_list = $this->getCustomFields();
|
||||
$pull = $this->getPullRequest();
|
||||
|
||||
$header = $this->buildHeader($pull);
|
||||
|
||||
$action_list = $this->buildActionList($pull);
|
||||
|
||||
$property_list = id(new PHUIPropertyListView())
|
||||
->setUser($viewer)
|
||||
->setActionList($action_list);
|
||||
|
||||
$field_list->appendFieldsToPropertyList(
|
||||
$pull,
|
||||
$viewer,
|
||||
$property_list);
|
||||
|
||||
$warnings = $this->getWarnings($pull);
|
||||
|
||||
if ($this->getIsListView()) {
|
||||
Javelin::initBehavior('releeph-request-state-change');
|
||||
}
|
||||
|
||||
return id(new PHUIObjectBoxView())
|
||||
->setHeader($header)
|
||||
->setFormErrors($warnings)
|
||||
->addSigil('releeph-request-box')
|
||||
->setMetadata(array('uri' => '/'.$pull->getMonogram()))
|
||||
->appendChild($property_list);
|
||||
}
|
||||
|
||||
private function buildHeader(ReleephRequest $pull) {
|
||||
$header_text = $pull->getSummaryForDisplay();
|
||||
if ($this->getIsListView()) {
|
||||
$header_text = phutil_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => '/'.$pull->getMonogram(),
|
||||
),
|
||||
$header_text);
|
||||
}
|
||||
|
||||
$header = id(new PHUIHeaderView())
|
||||
->setHeader($header_text)
|
||||
->setUser($this->getUser())
|
||||
->setPolicyObject($pull);
|
||||
|
||||
switch ($pull->getStatus()) {
|
||||
case ReleephRequestStatus::STATUS_REQUESTED:
|
||||
$icon = 'open';
|
||||
$color = null;
|
||||
break;
|
||||
case ReleephRequestStatus::STATUS_REJECTED:
|
||||
$icon = 'reject';
|
||||
$color = 'red';
|
||||
break;
|
||||
case ReleephRequestStatus::STATUS_PICKED:
|
||||
$icon = 'accept';
|
||||
$color = 'green';
|
||||
break;
|
||||
case ReleephRequestStatus::STATUS_REVERTED:
|
||||
case ReleephRequestStatus::STATUS_ABANDONED:
|
||||
$icon = 'reject';
|
||||
$color = 'dark';
|
||||
break;
|
||||
case ReleephRequestStatus::STATUS_NEEDS_PICK:
|
||||
$icon = 'warning';
|
||||
$color = 'green';
|
||||
break;
|
||||
case ReleephRequestStatus::STATUS_NEEDS_REVERT:
|
||||
$icon = 'warning';
|
||||
$color = 'red';
|
||||
break;
|
||||
default:
|
||||
$icon = 'question';
|
||||
$color = null;
|
||||
break;
|
||||
}
|
||||
$text = ReleephRequestStatus::getStatusDescriptionFor($pull->getStatus());
|
||||
$header->setStatus($icon, $color, $text);
|
||||
|
||||
if ($this->getIsListView()) {
|
||||
$header->setObjectName($pull->getMonogram());
|
||||
}
|
||||
|
||||
return $header;
|
||||
}
|
||||
|
||||
private function buildActionList(ReleephRequest $pull) {
|
||||
$viewer = $this->getUser();
|
||||
$id = $pull->getID();
|
||||
|
||||
$edit_uri = '/releeph/request/edit/'.$id.'/';
|
||||
|
||||
$view = id(new PhabricatorActionListView())
|
||||
->setUser($viewer);
|
||||
|
||||
$product = $pull->getBranch()->getProduct();
|
||||
$viewer_is_pusher = $product->isAuthoritativePHID($viewer->getPHID());
|
||||
$viewer_is_requestor = ($pull->getRequestUserPHID() == $viewer->getPHID());
|
||||
|
||||
if ($viewer_is_pusher) {
|
||||
$yes_text = pht('Approve Pull');
|
||||
$no_text = pht('Reject Pull');
|
||||
$yes_icon = 'check';
|
||||
$no_icon = 'delete';
|
||||
} else if ($viewer_is_requestor) {
|
||||
$yes_text = pht('Request Pull');
|
||||
$no_text = pht('Cancel Pull');
|
||||
$yes_icon = 'ok';
|
||||
$no_icon = 'delete';
|
||||
} else {
|
||||
$yes_text = pht('Support Pull');
|
||||
$no_text = pht('Discourage Pull');
|
||||
$yes_icon = 'like';
|
||||
$no_icon = 'dislike';
|
||||
}
|
||||
|
||||
$yes_href = '/releeph/request/action/want/'.$id.'/';
|
||||
$no_href = '/releeph/request/action/pass/'.$id.'/';
|
||||
|
||||
$intents = $pull->getUserIntents();
|
||||
$current_intent = idx($intents, $viewer->getPHID());
|
||||
|
||||
$yes_disabled = ($current_intent == ReleephRequest::INTENT_WANT);
|
||||
$no_disabled = ($current_intent == ReleephRequest::INTENT_PASS);
|
||||
|
||||
$use_workflow = (!$this->getIsListView());
|
||||
|
||||
$view->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setName($yes_text)
|
||||
->setHref($yes_href)
|
||||
->setWorkflow($use_workflow)
|
||||
->setRenderAsForm($use_workflow)
|
||||
->setDisabled($yes_disabled)
|
||||
->addSigil('releeph-request-state-change')
|
||||
->addSigil('want')
|
||||
->setIcon($yes_icon));
|
||||
|
||||
$view->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setName($no_text)
|
||||
->setHref($no_href)
|
||||
->setWorkflow($use_workflow)
|
||||
->setRenderAsForm($use_workflow)
|
||||
->setDisabled($no_disabled)
|
||||
->addSigil('releeph-request-state-change')
|
||||
->addSigil('pass')
|
||||
->setIcon($no_icon));
|
||||
|
||||
|
||||
if ($viewer_is_pusher || $viewer_is_requestor) {
|
||||
|
||||
$pulled_href = '/releeph/request/action/mark-manually-picked/'.$id.'/';
|
||||
$revert_href = '/releeph/request/action/mark-manually-reverted/'.$id.'/';
|
||||
|
||||
if ($pull->getInBranch()) {
|
||||
$view->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setName(pht('Mark as Reverted'))
|
||||
->setHref($revert_href)
|
||||
->setWorkflow($use_workflow)
|
||||
->setRenderAsForm($use_workflow)
|
||||
->addSigil('releeph-request-state-change')
|
||||
->addSigil('mark-manually-reverted')
|
||||
->setIcon($no_icon));
|
||||
} else {
|
||||
$view->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setName(pht('Mark as Pulled'))
|
||||
->setHref($pulled_href)
|
||||
->setWorkflow($use_workflow)
|
||||
->setRenderAsForm($use_workflow)
|
||||
->addSigil('releeph-request-state-change')
|
||||
->addSigil('mark-manually-picked')
|
||||
->setIcon('warning'));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!$this->getIsListView()) {
|
||||
$view->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setName(pht('Edit Pull Request'))
|
||||
->setIcon('edit')
|
||||
->setHref($edit_uri));
|
||||
}
|
||||
|
||||
return $view;
|
||||
}
|
||||
|
||||
private function getWarnings(ReleephRequest $pull) {
|
||||
$warnings = array();
|
||||
|
||||
switch ($pull->getStatus()) {
|
||||
case ReleephRequestStatus::STATUS_NEEDS_PICK:
|
||||
if ($pull->getPickStatus() == ReleephRequest::PICK_FAILED) {
|
||||
$warnings[] = pht('Last pull failed!');
|
||||
}
|
||||
break;
|
||||
case ReleephRequestStatus::STATUS_NEEDS_REVERT:
|
||||
if ($pull->getPickStatus() == ReleephRequest::REVERT_FAILED) {
|
||||
$warnings[] = pht('Last revert failed!');
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return $warnings;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,99 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class ReleephRequestIntentsView extends AphrontView {
|
||||
|
||||
private $releephRequest;
|
||||
private $releephProject;
|
||||
|
||||
public function setReleephRequest(ReleephRequest $rq) {
|
||||
$this->releephRequest = $rq;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setReleephProject(ReleephProject $rp) {
|
||||
$this->releephProject = $rp;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function render() {
|
||||
require_celerity_resource('releeph-intents');
|
||||
|
||||
return phutil_tag(
|
||||
'div',
|
||||
array(
|
||||
'class' => 'releeph-intents',
|
||||
),
|
||||
array(
|
||||
$this->renderIntentList(ReleephRequest::INTENT_WANT),
|
||||
$this->renderIntentList(ReleephRequest::INTENT_PASS)
|
||||
));
|
||||
}
|
||||
|
||||
private function renderIntentList($render_intent) {
|
||||
if (!$this->releephProject) {
|
||||
throw new Exception("Must call setReleephProject() first!");
|
||||
}
|
||||
|
||||
$project = $this->releephProject;
|
||||
$request = $this->releephRequest;
|
||||
$handles = $request->getHandles();
|
||||
|
||||
$pusher_links = array();
|
||||
$user_links = array();
|
||||
|
||||
$intents = $request->getUserIntents();
|
||||
foreach ($intents as $user_phid => $user_intent) {
|
||||
if ($user_intent == $render_intent) {
|
||||
if ($project->isAuthoritativePHID($user_phid)) {
|
||||
$pusher_links[] = phutil_tag(
|
||||
'span',
|
||||
array(
|
||||
'class' => 'pusher'
|
||||
),
|
||||
$handles[$user_phid]->renderLink());
|
||||
} else {
|
||||
$class = 'bystander';
|
||||
if ($request->getRequestUserPHID() == $user_phid) {
|
||||
$class = 'requestor';
|
||||
}
|
||||
$user_links[] = phutil_tag(
|
||||
'span',
|
||||
array(
|
||||
'class' => $class,
|
||||
),
|
||||
$handles[$user_phid]->renderLink());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Don't render anything
|
||||
if (!$pusher_links && !$user_links) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$links = array_merge($pusher_links, $user_links);
|
||||
if ($links) {
|
||||
$markup = $links;
|
||||
} else {
|
||||
$markup = array(' ');
|
||||
}
|
||||
|
||||
// Stick an arrow up front
|
||||
$arrow_class = 'arrow '.$render_intent;
|
||||
array_unshift($markup, phutil_tag(
|
||||
'div',
|
||||
array(
|
||||
'class' => $arrow_class,
|
||||
),
|
||||
''));
|
||||
|
||||
return phutil_tag(
|
||||
'div',
|
||||
array(
|
||||
'class' => 'intents',
|
||||
),
|
||||
$markup);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class ReleephRequestStatusView extends AphrontView {
|
||||
|
||||
private $releephRequest;
|
||||
|
||||
public function setReleephRequest(ReleephRequest $rq) {
|
||||
$this->releephRequest = $rq;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function render() {
|
||||
require_celerity_resource('releeph-status');
|
||||
|
||||
$request = $this->releephRequest;
|
||||
$status = $request->getStatus();
|
||||
$pick_status = $request->getPickStatus();
|
||||
|
||||
$description = ReleephRequestStatus::getStatusDescriptionFor($status);
|
||||
|
||||
$warning = null;
|
||||
|
||||
if ($status == ReleephRequestStatus::STATUS_NEEDS_PICK) {
|
||||
if ($pick_status == ReleephRequest::PICK_FAILED) {
|
||||
$warning = 'Last pick failed!';
|
||||
}
|
||||
} elseif ($status == ReleephRequestStatus::STATUS_NEEDS_REVERT) {
|
||||
if ($pick_status == ReleephRequest::REVERT_FAILED) {
|
||||
$warning = 'Last revert failed!';
|
||||
}
|
||||
}
|
||||
|
||||
return phutil_tag(
|
||||
'div',
|
||||
array(
|
||||
'class' => 'releeph-status',
|
||||
),
|
||||
array(
|
||||
phutil_tag(
|
||||
'div',
|
||||
array(
|
||||
'class' => 'description',
|
||||
),
|
||||
$description),
|
||||
phutil_tag(
|
||||
'div',
|
||||
array(
|
||||
'class' => 'warning',
|
||||
),
|
||||
$warning)));
|
||||
}
|
||||
|
||||
}
|
|
@ -1,121 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class ReleephRequestHeaderListView
|
||||
extends AphrontView {
|
||||
|
||||
private $releephProject;
|
||||
private $releephBranch;
|
||||
private $releephRequests;
|
||||
private $aphrontRequest;
|
||||
private $reload = false;
|
||||
|
||||
private $errors = array();
|
||||
|
||||
public function setReleephProject(ReleephProject $rp) {
|
||||
$this->releephProject = $rp;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setReleephBranch(ReleephBranch $rb) {
|
||||
$this->releephBranch = $rb;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setReleephRequests(array $requests) {
|
||||
assert_instances_of($requests, 'ReleephRequest');
|
||||
$this->releephRequests = $requests;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setAphrontRequest(AphrontRequest $request) {
|
||||
$this->aphrontRequest = $request;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setReloadOnStateChange($bool) {
|
||||
$this->reload = $bool;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function render() {
|
||||
$views = $this->renderInner();
|
||||
require_celerity_resource('phabricator-notification-css');
|
||||
Javelin::initBehavior('releeph-request-state-change', array(
|
||||
'reload' => $this->reload,
|
||||
));
|
||||
|
||||
$error_view = null;
|
||||
if ($this->errors) {
|
||||
$error_view = id(new AphrontErrorView())
|
||||
->setTitle('Bulk load errors')
|
||||
->setSeverity(AphrontErrorView::SEVERITY_WARNING)
|
||||
->setErrors($this->errors)
|
||||
->render();
|
||||
}
|
||||
|
||||
$list = phutil_tag(
|
||||
'div',
|
||||
array(
|
||||
'data-sigil' => 'releeph-request-header-list',
|
||||
),
|
||||
$views);
|
||||
|
||||
return array($error_view, $list);
|
||||
}
|
||||
|
||||
/**
|
||||
* Required for generating markup for ReleephRequestActionController.
|
||||
*
|
||||
* That controller just needs the markup, and doesn't need to start the
|
||||
* javelin behavior.
|
||||
*/
|
||||
public function renderInner() {
|
||||
$selector = $this->releephProject->getReleephFieldSelector();
|
||||
$fields = $selector->getFieldSpecifications();
|
||||
foreach ($fields as $field) {
|
||||
$field
|
||||
->setReleephProject($this->releephProject)
|
||||
->setReleephBranch($this->releephBranch)
|
||||
->setUser($this->user);
|
||||
try {
|
||||
$field->bulkLoad($this->releephRequests);
|
||||
} catch (Exception $ex) {
|
||||
$this->errors[] = $ex;
|
||||
}
|
||||
}
|
||||
|
||||
$engine = id(new PhabricatorMarkupEngine())
|
||||
->setViewer($this->getUser());
|
||||
|
||||
$views = array();
|
||||
foreach ($this->releephRequests as $releeph_request) {
|
||||
$our_fields = array();
|
||||
foreach ($fields as $key => $field) {
|
||||
$our_fields[$key] = clone $field;
|
||||
}
|
||||
|
||||
foreach ($our_fields as $field) {
|
||||
if ($field->shouldMarkup()) {
|
||||
$field
|
||||
->setReleephRequest($releeph_request)
|
||||
->setMarkupEngine($engine);
|
||||
}
|
||||
}
|
||||
|
||||
$our_field_groups = $selector->arrangeFieldsForHeaderView($our_fields);
|
||||
|
||||
$views[] = id(new ReleephRequestHeaderView())
|
||||
->setUser($this->user)
|
||||
->setAphrontRequest($this->aphrontRequest)
|
||||
->setReleephProject($this->releephProject)
|
||||
->setReleephBranch($this->releephBranch)
|
||||
->setReleephRequest($releeph_request)
|
||||
->setReleephFieldGroups($our_field_groups);
|
||||
}
|
||||
|
||||
$engine->process();
|
||||
|
||||
return $views;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,323 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class ReleephRequestHeaderView extends AphrontView {
|
||||
|
||||
const THROW_PARAM = '__releeph_throw';
|
||||
|
||||
private $aphrontRequest;
|
||||
private $releephRequest;
|
||||
private $releephBranch;
|
||||
private $releephProject;
|
||||
private $fieldGroups;
|
||||
|
||||
public function setAphrontRequest(AphrontRequest $request) {
|
||||
$this->aphrontRequest = $request;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setReleephProject(ReleephProject $rp) {
|
||||
$this->releephProject = $rp;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setReleephBranch(ReleephBranch $rb) {
|
||||
$this->releephBranch = $rb;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setReleephRequest(ReleephRequest $rr) {
|
||||
$this->releephRequest = $rr;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setReleephFieldGroups(array $field_groups) {
|
||||
$this->fieldGroups = $field_groups;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function render() {
|
||||
require_celerity_resource('releeph-core');
|
||||
$all_properties_table = $this->renderFields();
|
||||
|
||||
require_celerity_resource('releeph-colors');
|
||||
$status = $this->releephRequest->getStatus();
|
||||
$rr_div_class =
|
||||
'releeph-request-header '.
|
||||
'releeph-request-header-border '.
|
||||
'releeph-border-color-'.
|
||||
ReleephRequestStatus::getStatusClassSuffixFor($status);
|
||||
|
||||
$hidden_link = phutil_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => '/RQ'.$this->releephRequest->getID(),
|
||||
'target' => '_blank',
|
||||
'data-sigil' => 'hidden-link',
|
||||
),
|
||||
'');
|
||||
|
||||
$focus_char = phutil_tag(
|
||||
'div',
|
||||
array(
|
||||
'class' => 'focus-char',
|
||||
'data-sigil' => 'focus-char',
|
||||
),
|
||||
"\xE2\x98\x86");
|
||||
|
||||
$rr_div = phutil_tag(
|
||||
'div',
|
||||
array(
|
||||
'data-sigil' => 'releeph-request-header',
|
||||
'class' => $rr_div_class,
|
||||
),
|
||||
array(
|
||||
phutil_tag(
|
||||
'div',
|
||||
array(),
|
||||
array(
|
||||
phutil_tag(
|
||||
'h1',
|
||||
array(),
|
||||
array(
|
||||
$focus_char,
|
||||
$this->renderTitleLink(),
|
||||
$hidden_link
|
||||
)),
|
||||
$all_properties_table,
|
||||
)),
|
||||
phutil_tag(
|
||||
'div',
|
||||
array(
|
||||
'class' => 'button-divider',
|
||||
),
|
||||
$this->renderActionButtonsTable())));
|
||||
|
||||
return $rr_div;
|
||||
}
|
||||
|
||||
private function renderFields() {
|
||||
$field_row_groups = $this->fieldGroups;
|
||||
|
||||
$trs = array();
|
||||
foreach ($field_row_groups as $field_column_group) {
|
||||
$tds = array();
|
||||
foreach ($field_column_group as $side => $fields) {
|
||||
$rows = array();
|
||||
foreach ($fields as $field) {
|
||||
$rows[] = $this->renderOneField($field);
|
||||
}
|
||||
$pane = phutil_tag(
|
||||
'table',
|
||||
array(
|
||||
'class' => 'fields',
|
||||
),
|
||||
$rows);
|
||||
$tds[] = phutil_tag(
|
||||
'td',
|
||||
array(
|
||||
'class' => 'side '.$side,
|
||||
),
|
||||
$pane);
|
||||
}
|
||||
$trs[] = phutil_tag(
|
||||
'tr',
|
||||
array(),
|
||||
$tds);
|
||||
}
|
||||
|
||||
return phutil_tag(
|
||||
'table',
|
||||
array(
|
||||
'class' => 'panes',
|
||||
),
|
||||
$trs);
|
||||
}
|
||||
|
||||
private function renderOneField(ReleephFieldSpecification $field) {
|
||||
$field
|
||||
->setUser($this->user)
|
||||
->setReleephProject($this->releephProject)
|
||||
->setReleephBranch($this->releephBranch)
|
||||
->setReleephRequest($this->releephRequest);
|
||||
|
||||
$label = $field->renderLabelForHeaderView();
|
||||
try {
|
||||
$value = $field->renderValueForHeaderView();
|
||||
} catch (Exception $ex) {
|
||||
if ($this->aphrontRequest->getInt(self::THROW_PARAM)) {
|
||||
throw $ex;
|
||||
} else {
|
||||
$value = $this->renderExceptionIcon($ex);
|
||||
}
|
||||
}
|
||||
|
||||
if ($value) {
|
||||
if (!$label) {
|
||||
return phutil_tag(
|
||||
'tr',
|
||||
array(),
|
||||
phutil_tag('td', array('colspan' => 2), $value));
|
||||
} else {
|
||||
return phutil_tag(
|
||||
'tr',
|
||||
array(),
|
||||
array(
|
||||
phutil_tag('th', array(), $label),
|
||||
phutil_tag('td', array(), $value)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function renderExceptionIcon(Exception $ex) {
|
||||
Javelin::initBehavior('phabricator-tooltips');
|
||||
require_celerity_resource('aphront-tooltip-css');
|
||||
$throw_uri = $this
|
||||
->aphrontRequest
|
||||
->getRequestURI()
|
||||
->setQueryParam(self::THROW_PARAM, 1);
|
||||
|
||||
$message = $ex->getMessage();
|
||||
if (!$message) {
|
||||
$message = get_class($ex).' with no message.';
|
||||
}
|
||||
|
||||
return javelin_tag(
|
||||
'a',
|
||||
array(
|
||||
'class' => 'releeph-field-error',
|
||||
'sigil' => 'has-tooltip',
|
||||
'meta' => array(
|
||||
'tip' => $message,
|
||||
'size' => 400,
|
||||
'align' => 'E',
|
||||
),
|
||||
'href' => $throw_uri,
|
||||
),
|
||||
'!!!');
|
||||
}
|
||||
|
||||
private function renderTitleLink() {
|
||||
$rq_id = $this->releephRequest->getID();
|
||||
$summary = $this->releephRequest->getSummaryForDisplay();
|
||||
return phutil_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => '/RQ'.$rq_id,
|
||||
),
|
||||
hsprintf(
|
||||
'RQ%d: %s',
|
||||
$rq_id,
|
||||
$summary));
|
||||
}
|
||||
|
||||
private function renderActionButtonsTable() {
|
||||
$left_buttons = array();
|
||||
$right_buttons = array();
|
||||
|
||||
$user_phid = $this->user->getPHID();
|
||||
$is_pusher = $this->releephProject->isAuthoritativePHID($user_phid);
|
||||
$is_requestor = $this->releephRequest->getRequestUserPHID() === $user_phid;
|
||||
|
||||
$current_intent = idx(
|
||||
$this->releephRequest->getUserIntents(),
|
||||
$this->user->getPHID());
|
||||
|
||||
if ($is_pusher) {
|
||||
$left_buttons[] = $this->renderIntentButton(true, 'Approve', 'green');
|
||||
$left_buttons[] = $this->renderIntentButton(false, 'Reject');
|
||||
} else {
|
||||
if ($is_requestor) {
|
||||
$right_buttons[] = $this->renderIntentButton(true, 'Request');
|
||||
$right_buttons[] = $this->renderIntentButton(false, 'Remove');
|
||||
} else {
|
||||
$right_buttons[] = $this->renderIntentButton(true, 'Want');
|
||||
$right_buttons[] = $this->renderIntentButton(false, 'Pass');
|
||||
}
|
||||
}
|
||||
|
||||
// Allow the pusher to mark a request as manually picked or reverted.
|
||||
if ($is_pusher || $is_requestor) {
|
||||
if ($this->releephRequest->getInBranch()) {
|
||||
$left_buttons[] = $this->renderActionButton(
|
||||
'Mark Manually Reverted',
|
||||
'mark-manually-reverted');
|
||||
} else {
|
||||
$left_buttons[] = $this->renderActionButton(
|
||||
'Mark Manually Picked',
|
||||
'mark-manually-picked');
|
||||
}
|
||||
}
|
||||
|
||||
$right_buttons[] = phutil_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => '/releeph/request/edit/'.$this->releephRequest->getID().'/',
|
||||
'class' => 'small blue button',
|
||||
),
|
||||
'Edit');
|
||||
|
||||
if (!$left_buttons && !$right_buttons) {
|
||||
return;
|
||||
}
|
||||
|
||||
$cells = array();
|
||||
foreach ($left_buttons as $button) {
|
||||
$cells[] = phutil_tag('td', array('align' => 'left'), $button);
|
||||
}
|
||||
$cells[] = phutil_tag('td', array('class' => 'wide'), '');
|
||||
foreach ($right_buttons as $button) {
|
||||
$cells[] = phutil_tag('td', array('align' => 'right'), $button);
|
||||
}
|
||||
|
||||
$table = phutil_tag(
|
||||
'table',
|
||||
array(
|
||||
'class' => 'buttons',
|
||||
),
|
||||
phutil_tag(
|
||||
'tr',
|
||||
array(),
|
||||
$cells));
|
||||
|
||||
return $table;
|
||||
}
|
||||
|
||||
private function renderIntentButton($want, $name, $class = null) {
|
||||
$current_intent = idx(
|
||||
$this->releephRequest->getUserIntents(),
|
||||
$this->user->getPHID());
|
||||
|
||||
if ($current_intent) {
|
||||
// If this is a "want" button, and they already want it, disable the
|
||||
// button (and vice versa for the "pass" case.)
|
||||
if (($want && $current_intent == ReleephRequest::INTENT_WANT) ||
|
||||
(!$want && $current_intent == ReleephRequest::INTENT_PASS)) {
|
||||
|
||||
$class .= ' disabled';
|
||||
}
|
||||
}
|
||||
|
||||
$action = $want ? 'want' : 'pass';
|
||||
return $this->renderActionButton($name, $action, $class);
|
||||
}
|
||||
|
||||
private function renderActionButton($name, $action, $class=null) {
|
||||
$attributes = array(
|
||||
'class' => 'small button '.$class,
|
||||
'sigil' => 'releeph-request-state-change '.$action,
|
||||
'meta' => null,
|
||||
);
|
||||
|
||||
if ($class != 'disabled') {
|
||||
// NB the trailing slash on $uri is critical, otherwise the URI will
|
||||
// redirect to one with a slash, which will turn our GET into a POST.
|
||||
$attributes['meta'] = sprintf(
|
||||
'/releeph/request/action/%s/%d/',
|
||||
$action,
|
||||
$this->releephRequest->getID());
|
||||
}
|
||||
|
||||
return javelin_tag('a', $attributes, $name);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,137 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorNoteExample extends PhabricatorUIExample {
|
||||
|
||||
public function getName() {
|
||||
return "Notes";
|
||||
}
|
||||
|
||||
public function getDescription() {
|
||||
return pht('Bounded boxes of text.');
|
||||
}
|
||||
|
||||
public function renderExample() {
|
||||
$short_note = id(new AphrontNoteView())
|
||||
->setTitle(pht('Short note'))
|
||||
->appendChild('xxxx xx x xxxxx xxxx');
|
||||
|
||||
$longer_note = id(new AphrontNoteView())
|
||||
->setTitle(pht('Longer note'))
|
||||
->appendChild($this->buildParagraphs(2));
|
||||
|
||||
$wide_url = 'protocol://www.'.str_repeat('x', 100).'.com/';
|
||||
|
||||
$oversize_note = id(new AphrontNoteView())
|
||||
->setTitle(pht('Oversize note'))
|
||||
->appendChild(
|
||||
$this->buildParagraphs(2).
|
||||
$wide_url."\n\n".
|
||||
$this->buildParagraphs(15));
|
||||
|
||||
$out = array();
|
||||
|
||||
$out[] = id(new AphrontPanelView())
|
||||
->setHeader(pht('Unbounded Oversize Note'))
|
||||
->appendChild($oversize_note);
|
||||
|
||||
$out[] = id(new AphrontPanelView())
|
||||
->setHeader(pht('Short notes'))
|
||||
->appendChild(
|
||||
$this->renderTable(
|
||||
array(array($short_note, $short_note))));
|
||||
|
||||
$out[] = id(new AphrontPanelView())
|
||||
->setHeader(pht('Mixed notes'))
|
||||
->appendChild(
|
||||
$this->renderTable(
|
||||
array(
|
||||
array($longer_note, $short_note),
|
||||
array($short_note, $short_note)
|
||||
)));
|
||||
|
||||
$out[] = id(new AphrontPanelView())
|
||||
->setHeader(pht('Oversize notes'))
|
||||
->appendChild(
|
||||
$this->renderTable(
|
||||
array(
|
||||
array($oversize_note, $short_note),
|
||||
array($short_note, $oversize_note)
|
||||
)));
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
private function renderTable($rows) {
|
||||
static $td_style = '
|
||||
width: 50%;
|
||||
max-width: 1em;
|
||||
';
|
||||
|
||||
$trs = array();
|
||||
foreach ($rows as $index => $row) {
|
||||
$count = $index + 1;
|
||||
list($left, $right) = $row;
|
||||
$trs[] = phutil_tag(
|
||||
'tr',
|
||||
array(),
|
||||
array(
|
||||
phutil_tag(
|
||||
'th',
|
||||
array(),
|
||||
"Row {$count}"),
|
||||
phutil_tag('td')));
|
||||
|
||||
$trs[] = phutil_tag(
|
||||
'tr',
|
||||
array(),
|
||||
array(
|
||||
phutil_tag(
|
||||
'td',
|
||||
array(
|
||||
'style' => $td_style,
|
||||
),
|
||||
$left->render()),
|
||||
phutil_tag(
|
||||
'td',
|
||||
array(
|
||||
'style' => $td_style,
|
||||
),
|
||||
$right->render())));
|
||||
}
|
||||
|
||||
return phutil_tag(
|
||||
'table',
|
||||
array(
|
||||
'style' => 'width: 80%;'
|
||||
),
|
||||
$trs);
|
||||
}
|
||||
|
||||
private function buildParagraphs($num_paragraphs) {
|
||||
$body = '';
|
||||
for ($pp = 0; $pp < $num_paragraphs; $pp++) {
|
||||
$scale = 50 * ($pp / 2);
|
||||
$num_words = 30 + self::getRandom(0, $scale);
|
||||
for ($ii = 0; $ii < $num_words; $ii++) {
|
||||
$word = str_repeat('x', self::getRandom(3, 8));
|
||||
$body .= $word.' ';
|
||||
}
|
||||
$body .= "\n\n";
|
||||
}
|
||||
return $body;
|
||||
}
|
||||
|
||||
private static function getRandom($lower, $upper) {
|
||||
// The ZX Spectrum's PRNG!
|
||||
static $nn = 65537;
|
||||
static $gg = 75;
|
||||
static $ii = 1;
|
||||
$ii = ($ii * $gg) % $nn;
|
||||
if ($lower == $upper) {
|
||||
return $lower;
|
||||
} else {
|
||||
return $lower + ($ii % ($upper - $lower));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -11,6 +11,7 @@ final class PhabricatorActionView extends AphrontView {
|
|||
private $renderAsForm;
|
||||
private $download;
|
||||
private $objectURI;
|
||||
private $sigils = array();
|
||||
|
||||
public function setObjectURI($object_uri) {
|
||||
$this->objectURI = $object_uri;
|
||||
|
@ -34,6 +35,11 @@ final class PhabricatorActionView extends AphrontView {
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function addSigil($sigil) {
|
||||
$this->sigils[] = $sigil;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the user is not logged in and the action is relatively complicated,
|
||||
* give them a generic login link that will re-direct to the page they're
|
||||
|
@ -98,6 +104,21 @@ final class PhabricatorActionView extends AphrontView {
|
|||
}
|
||||
|
||||
if ($this->href) {
|
||||
|
||||
$sigils = array();
|
||||
if ($this->workflow) {
|
||||
$sigils[] = 'workflow';
|
||||
}
|
||||
if ($this->download) {
|
||||
$sigils[] = 'download';
|
||||
}
|
||||
|
||||
if ($this->sigils) {
|
||||
$sigils = array_merge($sigils, $this->sigils);
|
||||
}
|
||||
|
||||
$sigils = $sigils ? implode(' ', $sigils) : null;
|
||||
|
||||
if ($this->renderAsForm) {
|
||||
if (!$this->user) {
|
||||
throw new Exception(
|
||||
|
@ -111,20 +132,12 @@ final class PhabricatorActionView extends AphrontView {
|
|||
),
|
||||
$this->name);
|
||||
|
||||
$sigils = array();
|
||||
if ($this->workflow) {
|
||||
$sigils[] = 'workflow';
|
||||
}
|
||||
if ($this->download) {
|
||||
$sigils[] = 'download';
|
||||
}
|
||||
|
||||
$item = phabricator_form(
|
||||
$this->user,
|
||||
array(
|
||||
'action' => $this->getHref(),
|
||||
'method' => 'POST',
|
||||
'sigil' => implode(' ', $sigils),
|
||||
'sigil' => $sigils,
|
||||
),
|
||||
$item);
|
||||
} else {
|
||||
|
@ -133,7 +146,7 @@ final class PhabricatorActionView extends AphrontView {
|
|||
array(
|
||||
'href' => $this->getHref(),
|
||||
'class' => 'phabricator-action-view-item',
|
||||
'sigil' => $this->workflow ? 'workflow' : null,
|
||||
'sigil' => $sigils,
|
||||
),
|
||||
$this->name);
|
||||
}
|
||||
|
|
|
@ -11,10 +11,22 @@ final class PHUIObjectBoxView extends AphrontView {
|
|||
private $header;
|
||||
private $flush;
|
||||
private $id;
|
||||
private $sigils = array();
|
||||
private $metadata;
|
||||
|
||||
private $tabs = array();
|
||||
private $propertyLists = array();
|
||||
|
||||
public function addSigil($sigil) {
|
||||
$this->sigils[] = $sigil;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setMetadata(array $metadata) {
|
||||
$this->metadata = $metadata;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function addPropertyList(
|
||||
PHUIPropertyListView $property_list,
|
||||
$tab = null) {
|
||||
|
@ -246,6 +258,14 @@ final class PHUIObjectBoxView extends AphrontView {
|
|||
$content->addClass('phui-object-box-flush');
|
||||
}
|
||||
|
||||
foreach ($this->sigils as $sigil) {
|
||||
$content->addSigil($sigil);
|
||||
}
|
||||
|
||||
if ($this->metadata !== null) {
|
||||
$content->setMetadata($this->metadata);
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class AphrontNoteView extends AphrontView {
|
||||
|
||||
private $title;
|
||||
|
||||
public function setTitle($title) {
|
||||
$this->title = $title;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function render() {
|
||||
$title = phutil_tag(
|
||||
'div',
|
||||
array(
|
||||
'class' => 'title',
|
||||
),
|
||||
$this->title);
|
||||
|
||||
$inner = phutil_tag(
|
||||
'div',
|
||||
array(
|
||||
'class' => 'inner',
|
||||
),
|
||||
$this->renderChildren());
|
||||
|
||||
require_celerity_resource('aphront-notes');
|
||||
return phutil_tag(
|
||||
'div',
|
||||
array(
|
||||
'class' => 'aphront-note',
|
||||
),
|
||||
array(
|
||||
$title,
|
||||
$inner));
|
||||
}
|
||||
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
/**
|
||||
* @provides aphront-notes
|
||||
*/
|
||||
|
||||
div.aphront-note {
|
||||
margin: 1em;
|
||||
background: #ffc;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
|
||||
div.aphront-note div.title {
|
||||
margin: 0;
|
||||
padding: 0.2em 0.5em 0.2em;
|
||||
background: #ffd;
|
||||
border-bottom: 1px solid #ccc;
|
||||
color: {$lightgreytext};
|
||||
font-size: smaller;
|
||||
}
|
||||
|
||||
div.aphront-note div.inner {
|
||||
overflow: auto;
|
||||
padding: 0.5em;
|
||||
max-height: 25em;
|
||||
color: #333;
|
||||
font-size: smaller;
|
||||
}
|
|
@ -1,79 +0,0 @@
|
|||
/**
|
||||
* @provides releeph-branch
|
||||
*/
|
||||
|
||||
.releeph-branch-box {
|
||||
margin-bottom: .5em;
|
||||
padding: .5em .5em .5em;
|
||||
|
||||
border: 2px solid #d5d5d5;
|
||||
/*border-top-color: #D5D5D5;
|
||||
border-right-color: #BBB;
|
||||
border-bottom-color: #A4A4A4;
|
||||
border-left-color: #BBB;*/
|
||||
|
||||
background: #bbb;
|
||||
}
|
||||
|
||||
/* Types of branch */
|
||||
|
||||
.releeph-branch-box-named {
|
||||
background: #ddd;
|
||||
}
|
||||
|
||||
.releeph-branch-box-latest {
|
||||
background: #ffd;
|
||||
}
|
||||
|
||||
/* Branch symbolic name and full name */
|
||||
|
||||
.releeph-branch-box .names {
|
||||
width: 25em;
|
||||
float: left;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.releeph-branch-box .names h1 {
|
||||
font-size: 125%;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
.releeph-branch-box .names h2 {
|
||||
font-weight: normal;
|
||||
font-size: 85%;
|
||||
}
|
||||
|
||||
/* Date info */
|
||||
|
||||
.releeph-branch-box .date-info {
|
||||
width: 10%;
|
||||
float: left;
|
||||
color: #555;
|
||||
margin-bottom: .3em;
|
||||
}
|
||||
|
||||
/* Statistics table */
|
||||
|
||||
.releeph-branch-box .request-statistics {
|
||||
float: right;
|
||||
padding-right: 2em;
|
||||
font-size: 85%;
|
||||
}
|
||||
|
||||
.releeph-branch-box .request-statistics th {
|
||||
width: 1em;
|
||||
text-align: right;
|
||||
padding-right: .4em;
|
||||
padding-left: .4em;
|
||||
}
|
||||
|
||||
.releeph-branch-box .request-statistics td {
|
||||
white-space: nowrap;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/* Buttons */
|
||||
|
||||
.releeph-branch-box .buttons {
|
||||
float: right;
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
/**
|
||||
* @provides releeph-colors
|
||||
*/
|
||||
|
||||
.releeph-border-color-failed {
|
||||
border-color: #d2d;
|
||||
}
|
||||
|
||||
.releeph-border-color-requested {
|
||||
border-color: #ddd;
|
||||
}
|
||||
|
||||
.releeph-border-color-comment {
|
||||
border-color: #ddd;
|
||||
}
|
||||
|
||||
.releeph-border-color-needs-pick {
|
||||
border-color: #096;
|
||||
}
|
||||
|
||||
.releeph-border-color-rejected {
|
||||
border-color: #d00;
|
||||
}
|
||||
|
||||
.releeph-border-color-needs-revert {
|
||||
border-color: #d00;
|
||||
}
|
||||
|
||||
.releeph-border-color-abandoned {
|
||||
border-color: #222;
|
||||
}
|
||||
|
||||
.releeph-border-color-picked {
|
||||
border-color: #069;
|
||||
}
|
|
@ -2,119 +2,6 @@
|
|||
* @provides releeph-core
|
||||
*/
|
||||
|
||||
.releeph-request-header {
|
||||
margin: .5em 2em 3em;
|
||||
|
||||
/**
|
||||
* Copied from the old .differential-panel, present in commit
|
||||
* f04d8ab1a747dc9719d378d9286088b677ce224c
|
||||
*
|
||||
* (As is the <h1> code below)
|
||||
*/
|
||||
max-width: 1120px;
|
||||
border: 1px solid {$greytext}622;
|
||||
background: #efefdf;
|
||||
padding: 15px 20px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.releeph-request-header h1 {
|
||||
width: 100%;
|
||||
border-bottom: 1px solid #aaaa99;
|
||||
padding-bottom: 8px;
|
||||
margin-bottom: 8px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.releeph-request-header .focus-char {
|
||||
left: -10px;
|
||||
display: none;
|
||||
float: left;
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: -1em;
|
||||
|
||||
font-weight: bold;
|
||||
|
||||
color: #880;
|
||||
font-family: "Hiragino Kaku Gothic Pro", "Osaka", "Zapf Dingbats";
|
||||
}
|
||||
|
||||
.releeph-request-header.focus .focus-char {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.releeph-request-header-border {
|
||||
border-width: 1px 10px 1px;
|
||||
border-color: #ddd;
|
||||
}
|
||||
|
||||
|
||||
/* Laying out properties / fields */
|
||||
|
||||
.releeph-request-header table.panes {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.releeph-request-header table.panes td.side {
|
||||
width: 50%;
|
||||
max-width: 1em;
|
||||
}
|
||||
|
||||
.releeph-request-header table.panes td.side.left {
|
||||
padding-right: 20px;
|
||||
border-right: 3px solid #bbb;
|
||||
}
|
||||
|
||||
.releeph-request-header table.panes td.side.right {
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
.releeph-request-header table.panes td.side table.fields {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.releeph-request-header table.panes td.side table.fields tr {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.releeph-request-header table.panes td.side table.fields th {
|
||||
font-weight: bold;
|
||||
text-align: right;
|
||||
padding-right: 1em;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.releeph-request-header table.panes td.side table.fields td {
|
||||
width: 100%; /* wide! */
|
||||
max-width: 1em;
|
||||
}
|
||||
|
||||
|
||||
/* Buttons */
|
||||
|
||||
.releeph-request-header .button-divider {
|
||||
clear: both;
|
||||
margin-top: 1.5em;
|
||||
border-top: 1px solid #bbb;
|
||||
}
|
||||
|
||||
.releeph-request-header .buttons {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.releeph-request-header .buttons tr {
|
||||
padding: 1em;
|
||||
margin: 3em;
|
||||
}
|
||||
|
||||
.releeph-request-header .buttons td {
|
||||
padding: 1em .5em 0.2em;
|
||||
}
|
||||
|
||||
.releeph-request-header .buttons td.wide {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Colors: match differential colors */
|
||||
|
||||
|
@ -133,11 +20,11 @@
|
|||
|
||||
/* The diff size bar */
|
||||
|
||||
.releeph-request-header .diff-bar {
|
||||
.diff-bar {
|
||||
border: 0px;
|
||||
}
|
||||
|
||||
.releeph-request-header .diff-bar div {
|
||||
.diff-bar div {
|
||||
width: 100px;
|
||||
border: 1px solid;
|
||||
border-top-color: #A4A4A4;
|
||||
|
@ -149,51 +36,10 @@
|
|||
margin-right: 1em;
|
||||
}
|
||||
|
||||
.releeph-request-header .diff-bar div div {
|
||||
.diff-bar div div {
|
||||
height: 10px;
|
||||
}
|
||||
|
||||
.releeph-request-header .diff-bar span {
|
||||
.diff-bar span {
|
||||
color: #555;
|
||||
}
|
||||
|
||||
/* Rendering pick / commit errors, etc. */
|
||||
|
||||
.releeph-request-pick-failed-event h1:before {
|
||||
content: '\2014 ';
|
||||
}
|
||||
|
||||
.releeph-request-pick-failed-event h1:after {
|
||||
content: ' \2014';
|
||||
}
|
||||
|
||||
.releeph-request-pick-failed-event h1 {
|
||||
padding: 3px 10px 3px;
|
||||
margin-bottom: 0.5em;
|
||||
background: #ffb;
|
||||
font-size: small;
|
||||
}
|
||||
|
||||
.releeph-request-pick-failed-event div {
|
||||
font-family: monospace;
|
||||
margin-bottom: 1.5em;
|
||||
padding-left: 1em;
|
||||
width: 70em;
|
||||
}
|
||||
|
||||
/* History view of request */
|
||||
|
||||
.releeph-request-event-list {
|
||||
margin: .5em 2em .5em;
|
||||
}
|
||||
|
||||
|
||||
/* Shorten long header-text */
|
||||
|
||||
.releeph-header-text-truncated {
|
||||
width: 100%;
|
||||
float: left;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
|
|
@ -1,37 +0,0 @@
|
|||
/**
|
||||
* @provides releeph-intents
|
||||
*/
|
||||
|
||||
.releeph-intents .intents {
|
||||
clear: left;
|
||||
width: 100%;
|
||||
margin-top: 3px;
|
||||
}
|
||||
|
||||
.releeph-intents .arrow {
|
||||
float: left;
|
||||
clear: left;
|
||||
margin-right: 0.4em;
|
||||
padding: 8px;
|
||||
background: transparent 0 0 no-repeat;
|
||||
}
|
||||
|
||||
.releeph-intents .arrow.want {
|
||||
/* TODO: Icon. */
|
||||
}
|
||||
|
||||
.releeph-intents .arrow.pass {
|
||||
/* TODO: Icon. */
|
||||
}
|
||||
|
||||
.releeph-intents a {
|
||||
margin-right: 0.4em;
|
||||
}
|
||||
|
||||
.releeph-intents .pusher {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.releeph-intents .requestor {
|
||||
font-weight: normal;
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
/**
|
||||
* @provides releeph-project
|
||||
*/
|
||||
|
||||
/**
|
||||
* ...from aphront-transaction.css
|
||||
*/
|
||||
|
||||
.releeph-pusher {
|
||||
background: 2px 2px no-repeat;
|
||||
margin-top: 1em;
|
||||
margin-bottom: 1.25em;
|
||||
margin-right: 1em;
|
||||
min-height: 50px;
|
||||
padding: 2px 0px;
|
||||
|
||||
background-color: white;
|
||||
border: 2px solid gray;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.releeph-pusher-body {
|
||||
margin-left: 54px;
|
||||
padding: 1em;
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
/**
|
||||
* @provides releeph-status
|
||||
*/
|
||||
|
||||
.releeph-status .description {
|
||||
background: #d3d3d3;
|
||||
padding: 2px 6px 3px;
|
||||
margin-right: 4px;
|
||||
margin-bottom: 5px;
|
||||
display: block;
|
||||
float: left;
|
||||
border-radius: 8px;
|
||||
-moz-border-radius: 8px;
|
||||
-webkit-border-radius: 8px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.releeph-status .warning {
|
||||
margin-top: 2px;
|
||||
margin-left: 0.8em;
|
||||
float: left;
|
||||
padding-left: 22px;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 16px auto;
|
||||
|
||||
/* TODO: This had a background that's still at Facebook? */
|
||||
}
|
|
@ -7,3 +7,7 @@
|
|||
border-bottom: 1px solid {$blueborder};
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.phui-box.focus {
|
||||
box-shadow: 0 0 5px 5px rgba(255, 255, 0, 0.90);
|
||||
}
|
||||
|
|
|
@ -3,23 +3,17 @@
|
|||
* @requires javelin-behavior
|
||||
* javelin-dom
|
||||
* javelin-stratcom
|
||||
* javelin-request
|
||||
* javelin-workflow
|
||||
* javelin-util
|
||||
* phabricator-keyboard-shortcut
|
||||
* phabricator-notification
|
||||
*/
|
||||
|
||||
JX.behavior('releeph-request-state-change', function(config) {
|
||||
var root = JX.DOM.find(document, 'div', 'releeph-request-header-list');
|
||||
|
||||
function getRequestHeaderNodes() {
|
||||
return JX.DOM.scry(root, 'div', 'releeph-request-header');
|
||||
return JX.DOM.scry(document.body, 'div', 'releeph-request-box');
|
||||
}
|
||||
|
||||
/**
|
||||
* Keyboard navigation
|
||||
*/
|
||||
var keynav_cursor = -1;
|
||||
var notification = new JX.Notification();
|
||||
|
||||
function keynavJump(manager, delta) {
|
||||
// Calculate this everytime, because the DOM changes.
|
||||
|
@ -68,7 +62,7 @@ JX.behavior('releeph-request-state-change', function(config) {
|
|||
function keynavNavigateToRequestPage() {
|
||||
var headers = getRequestHeaderNodes();
|
||||
var header = headers[keynav_cursor];
|
||||
JX.DOM.find(header, 'a', 'hidden-link').click();
|
||||
window.open(JX.Stratcom.getData(header).uri);
|
||||
}
|
||||
|
||||
new JX.KeyboardShortcut('j', 'Jump to next request.')
|
||||
|
@ -95,51 +89,33 @@ JX.behavior('releeph-request-state-change', function(config) {
|
|||
})
|
||||
.register();
|
||||
|
||||
new JX.KeyboardShortcut('g', "Open selected request's page in a new tab.")
|
||||
new JX.KeyboardShortcut(
|
||||
['g', 'return'],
|
||||
"Open selected request's page in a new tab.")
|
||||
.setHandler(function(manager) {
|
||||
keynavNavigateToRequestPage();
|
||||
})
|
||||
.register();
|
||||
|
||||
|
||||
/**
|
||||
* AJAXy state changes for request buttons.
|
||||
*/
|
||||
function request_action(node, url) {
|
||||
var request = new JX.Request(url, function(response) {
|
||||
if (config.reload) {
|
||||
window.location.reload();
|
||||
} else {
|
||||
var markup = JX.$H(response.markup);
|
||||
JX.DOM.replace(node, markup);
|
||||
keynavMarkup();
|
||||
}
|
||||
});
|
||||
|
||||
request.send();
|
||||
function onresponse(box, response) {
|
||||
JX.DOM.replace(box, JX.$H(response.markup));
|
||||
keynavMarkup();
|
||||
}
|
||||
|
||||
JX.Stratcom.listen(
|
||||
'click',
|
||||
'releeph-request-state-change',
|
||||
function(e) {
|
||||
var button = e.getNode('releeph-request-state-change');
|
||||
var node = e.getNode('releeph-request-header');
|
||||
var url = e.getNodeData('releeph-request-state-change');
|
||||
e.kill();
|
||||
|
||||
// If this button has no action, or we've already responded to the first
|
||||
// click...
|
||||
if (!url || button.disabled) {
|
||||
return;
|
||||
}
|
||||
var box = e.getNode('releeph-request-box');
|
||||
var link = e.getNode('releeph-request-state-change');
|
||||
|
||||
// There's a race condition here though :(
|
||||
box.style.opacity = '0.5';
|
||||
|
||||
JX.DOM.alterClass(button, 'disabled', true);
|
||||
button.disabled = true;
|
||||
|
||||
e.prevent();
|
||||
request_action(node, url);
|
||||
}
|
||||
);
|
||||
JX.Workflow.newFromLink(link)
|
||||
.setData({render: true})
|
||||
.setHandler(JX.bind(null, onresponse, box))
|
||||
.start();
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue