Page MenuHomePhabricator

D16722.diff
No OneTemporary

D16722.diff

diff --git a/resources/celerity/map.php b/resources/celerity/map.php
--- a/resources/celerity/map.php
+++ b/resources/celerity/map.php
@@ -10,7 +10,7 @@
'conpherence.pkg.css' => '6412a825',
'conpherence.pkg.js' => 'cbe4d9be',
'core.pkg.css' => 'b99bbf5e',
- 'core.pkg.js' => '3eb7abf7',
+ 'core.pkg.js' => '2d9fc958',
'darkconsole.pkg.js' => 'e7393ebb',
'differential.pkg.css' => 'e1d704ce',
'differential.pkg.js' => '634399e9',
@@ -555,7 +555,7 @@
'rsrc/js/core/behavior-file-tree.js' => '88236f00',
'rsrc/js/core/behavior-form.js' => '5c54cbf3',
'rsrc/js/core/behavior-gesture.js' => '3ab51e2c',
- 'rsrc/js/core/behavior-global-drag-and-drop.js' => 'c8e57404',
+ 'rsrc/js/core/behavior-global-drag-and-drop.js' => '960f6a39',
'rsrc/js/core/behavior-high-security-warning.js' => 'a464fe03',
'rsrc/js/core/behavior-history-install.js' => '7ee2b591',
'rsrc/js/core/behavior-hovercard.js' => 'bcaccd64',
@@ -701,7 +701,7 @@
'javelin-behavior-error-log' => '6882e80a',
'javelin-behavior-event-all-day' => '937bb700',
'javelin-behavior-fancy-datepicker' => '568931f3',
- 'javelin-behavior-global-drag-and-drop' => 'c8e57404',
+ 'javelin-behavior-global-drag-and-drop' => '960f6a39',
'javelin-behavior-herald-rule-editor' => '7ebaeed3',
'javelin-behavior-high-security-warning' => 'a464fe03',
'javelin-behavior-history-install' => '7ee2b591',
@@ -1735,6 +1735,13 @@
'javelin-dom',
'phabricator-busy',
),
+ '960f6a39' => array(
+ 'javelin-behavior',
+ 'javelin-dom',
+ 'javelin-uri',
+ 'javelin-mask',
+ 'phabricator-drag-and-drop-file-upload',
+ ),
'988040b4' => array(
'javelin-install',
'javelin-dom',
@@ -1982,13 +1989,6 @@
'c7ccd872' => array(
'phui-fontkit-css',
),
- 'c8e57404' => array(
- 'javelin-behavior',
- 'javelin-dom',
- 'javelin-uri',
- 'javelin-mask',
- 'phabricator-drag-and-drop-file-upload',
- ),
'c90a04fc' => array(
'javelin-dom',
'javelin-dynval',
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -2109,6 +2109,7 @@
'PhabricatorCalendarImportDeleteTransaction' => 'applications/calendar/xaction/PhabricatorCalendarImportDeleteTransaction.php',
'PhabricatorCalendarImportDisableController' => 'applications/calendar/controller/PhabricatorCalendarImportDisableController.php',
'PhabricatorCalendarImportDisableTransaction' => 'applications/calendar/xaction/PhabricatorCalendarImportDisableTransaction.php',
+ 'PhabricatorCalendarImportDropController' => 'applications/calendar/controller/PhabricatorCalendarImportDropController.php',
'PhabricatorCalendarImportDuplicateLogType' => 'applications/calendar/importlog/PhabricatorCalendarImportDuplicateLogType.php',
'PhabricatorCalendarImportEditController' => 'applications/calendar/controller/PhabricatorCalendarImportEditController.php',
'PhabricatorCalendarImportEditEngine' => 'applications/calendar/editor/PhabricatorCalendarImportEditEngine.php',
@@ -6944,6 +6945,7 @@
'PhabricatorCalendarImportDeleteTransaction' => 'PhabricatorCalendarImportTransactionType',
'PhabricatorCalendarImportDisableController' => 'PhabricatorCalendarController',
'PhabricatorCalendarImportDisableTransaction' => 'PhabricatorCalendarImportTransactionType',
+ 'PhabricatorCalendarImportDropController' => 'PhabricatorCalendarController',
'PhabricatorCalendarImportDuplicateLogType' => 'PhabricatorCalendarImportLogType',
'PhabricatorCalendarImportEditController' => 'PhabricatorCalendarController',
'PhabricatorCalendarImportEditEngine' => 'PhabricatorEditEngine',
diff --git a/src/applications/calendar/application/PhabricatorCalendarApplication.php b/src/applications/calendar/application/PhabricatorCalendarApplication.php
--- a/src/applications/calendar/application/PhabricatorCalendarApplication.php
+++ b/src/applications/calendar/application/PhabricatorCalendarApplication.php
@@ -85,6 +85,8 @@
=> 'PhabricatorCalendarImportDisableController',
'delete/(?P<id>[1-9]\d*)/'
=> 'PhabricatorCalendarImportDeleteController',
+ 'drop/'
+ => 'PhabricatorCalendarImportDropController',
'log/' => array(
$this->getQueryRoutePattern()
=> 'PhabricatorCalendarImportLogListController',
diff --git a/src/applications/calendar/controller/PhabricatorCalendarEventListController.php b/src/applications/calendar/controller/PhabricatorCalendarEventListController.php
--- a/src/applications/calendar/controller/PhabricatorCalendarEventListController.php
+++ b/src/applications/calendar/controller/PhabricatorCalendarEventListController.php
@@ -7,6 +7,10 @@
return true;
}
+ public function isGlobalDragAndDropUploadEnabled() {
+ return true;
+ }
+
public function handleRequest(AphrontRequest $request) {
$year = $request->getURIData('year');
$month = $request->getURIData('month');
diff --git a/src/applications/calendar/controller/PhabricatorCalendarImportDropController.php b/src/applications/calendar/controller/PhabricatorCalendarImportDropController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/calendar/controller/PhabricatorCalendarImportDropController.php
@@ -0,0 +1,86 @@
+<?php
+
+final class PhabricatorCalendarImportDropController
+ extends PhabricatorCalendarController {
+
+ public function handleRequest(AphrontRequest $request) {
+ $viewer = $request->getViewer();
+
+ if (!$request->validateCSRF()) {
+ return new Aphront400Response();
+ }
+
+ $cancel_uri = $this->getApplicationURI();
+
+ $ids = $request->getStrList('h');
+ if ($ids) {
+ $files = id(new PhabricatorFileQuery())
+ ->setViewer($viewer)
+ ->withIDs($ids)
+ ->setRaisePolicyExceptions(true)
+ ->execute();
+ } else {
+ $files = array();
+ }
+
+ if (!$files) {
+ return $this->newDialog()
+ ->setTitle(pht('Nothing Uploaded'))
+ ->appendParagraph(
+ pht(
+ 'Drag and drop .ics files to upload them and import them into '.
+ 'Calendar.'))
+ ->addCancelButton($cancel_uri, pht('Done'));
+ }
+
+ $engine = new PhabricatorCalendarICSImportEngine();
+ $imports = array();
+ foreach ($files as $file) {
+ $import = PhabricatorCalendarImport::initializeNewCalendarImport(
+ $viewer,
+ clone $engine);
+
+ $xactions = array();
+ $xactions[] = id(new PhabricatorCalendarImportTransaction())
+ ->setTransactionType(
+ PhabricatorCalendarImportICSFileTransaction::TRANSACTIONTYPE)
+ ->setNewValue($file->getPHID());
+
+ $editor = id(new PhabricatorCalendarImportEditor())
+ ->setActor($viewer)
+ ->setContinueOnNoEffect(true)
+ ->setContinueOnMissingFields(true)
+ ->setContentSourceFromRequest($request);
+
+ $editor->applyTransactions($import, $xactions);
+
+ $imports[] = $import;
+ }
+
+ $import_phids = mpull($imports, 'getPHID');
+ $events = id(new PhabricatorCalendarEventQuery())
+ ->setViewer($viewer)
+ ->withImportSourcePHIDs($import_phids)
+ ->execute();
+
+ if (count($events) == 1) {
+ // The user imported exactly one event. This is consistent with dropping
+ // a .ics file from an email; just take them to the event.
+ $event = head($events);
+ $next_uri = $event->getURI();
+ } else if (count($imports) > 1) {
+ // The user imported multiple different files. Take them to a summary
+ // list of generated import activity.
+ $source_phids = implode(',', $import_phids);
+ $next_uri = '/calendar/import/log/?importSourcePHIDs='.$source_phids;
+ } else {
+ // The user imported one file, which had zero or more than one event.
+ // Take them to the import detail page.
+ $import = head($imports);
+ $next_uri = $import->getURI();
+ }
+
+ return id(new AphrontRedirectResponse())->setURI($next_uri);
+ }
+
+}
diff --git a/src/applications/calendar/import/PhabricatorCalendarImportEngine.php b/src/applications/calendar/import/PhabricatorCalendarImportEngine.php
--- a/src/applications/calendar/import/PhabricatorCalendarImportEngine.php
+++ b/src/applications/calendar/import/PhabricatorCalendarImportEngine.php
@@ -390,9 +390,9 @@
if ($rrule) {
$event->setRecurrenceRule($rrule);
- $until_datetime = $rrule->getUntil()
- ->setViewerTimezone($timezone);
+ $until_datetime = $rrule->getUntil();
if ($until_datetime) {
+ $until_datetime->setViewerTimezone($timezone);
$event->setUntilDateTime($until_datetime);
}
}
diff --git a/src/applications/calendar/query/PhabricatorCalendarEventSearchEngine.php b/src/applications/calendar/query/PhabricatorCalendarEventSearchEngine.php
--- a/src/applications/calendar/query/PhabricatorCalendarEventSearchEngine.php
+++ b/src/applications/calendar/query/PhabricatorCalendarEventSearchEngine.php
@@ -321,11 +321,9 @@
$list->addItem($item);
}
- $result = new PhabricatorApplicationSearchResultView();
- $result->setObjectList($list);
- $result->setNoDataString(pht('No events found.'));
-
- return $result;
+ return $this->newResultView()
+ ->setObjectList($list)
+ ->setNoDataString(pht('No events found.'));
}
private function buildCalendarMonthView(
@@ -393,10 +391,9 @@
->setProfileHeader(true)
->setHeader($from->format('F Y'));
- return id(new PhabricatorApplicationSearchResultView())
+ return $this->newResultView($month_view)
->setCrumbs($crumbs)
- ->setHeader($header)
- ->setContent($month_view);
+ ->setHeader($header);
}
private function buildCalendarDayView(
@@ -467,10 +464,9 @@
->setProfileHeader(true)
->setHeader($from->format('D, F jS'));
- return id(new PhabricatorApplicationSearchResultView())
+ return $this->newResultView($day_view)
->setCrumbs($crumbs)
- ->setHeader($header)
- ->setContent($day_view);
+ ->setHeader($header);
}
private function getDisplayYearAndMonthAndDay(
@@ -596,4 +592,26 @@
);
}
+
+ private function newResultView($content = null) {
+ // If we aren't rendering a dashboard panel, activate global drag-and-drop
+ // so you can import ".ics" files by dropping them directly onto the
+ // calendar.
+ if (!$this->isPanelContext()) {
+ $drop_upload = id(new PhabricatorGlobalUploadTargetView())
+ ->setViewer($this->requireViewer())
+ ->setHintText("\xE2\x87\xAA ".pht('Drop .ics Files to Import'))
+ ->setSubmitURI('/calendar/import/drop/')
+ ->setViewPolicy(PhabricatorPolicies::POLICY_NOONE);
+
+ $content = array(
+ $drop_upload,
+ $content,
+ );
+ }
+
+ return id(new PhabricatorApplicationSearchResultView())
+ ->setContent($content);
+ }
+
}
diff --git a/src/applications/calendar/storage/PhabricatorCalendarImport.php b/src/applications/calendar/storage/PhabricatorCalendarImport.php
--- a/src/applications/calendar/storage/PhabricatorCalendarImport.php
+++ b/src/applications/calendar/storage/PhabricatorCalendarImport.php
@@ -21,6 +21,7 @@
PhabricatorUser $actor,
PhabricatorCalendarImportEngine $engine) {
return id(new self())
+ ->setName('')
->setAuthorPHID($actor->getPHID())
->setViewPolicy($actor->getPHID())
->setEditPolicy($actor->getPHID())
diff --git a/src/applications/files/view/PhabricatorGlobalUploadTargetView.php b/src/applications/files/view/PhabricatorGlobalUploadTargetView.php
--- a/src/applications/files/view/PhabricatorGlobalUploadTargetView.php
+++ b/src/applications/files/view/PhabricatorGlobalUploadTargetView.php
@@ -14,6 +14,9 @@
final class PhabricatorGlobalUploadTargetView extends AphrontView {
private $showIfSupportedID;
+ private $hintText;
+ private $viewPolicy;
+ private $submitURI;
public function setShowIfSupportedID($show_if_supported_id) {
$this->showIfSupportedID = $show_if_supported_id;
@@ -24,8 +27,37 @@
return $this->showIfSupportedID;
}
+ public function setHintText($hint_text) {
+ $this->hintText = $hint_text;
+ return $this;
+ }
+
+ public function getHintText() {
+ return $this->hintText;
+ }
+
+ public function setViewPolicy($view_policy) {
+ $this->viewPolicy = $view_policy;
+ return $this;
+ }
+
+ public function getViewPolicy() {
+ return $this->viewPolicy;
+ }
+
+ public function setSubmitURI($submit_uri) {
+ $this->submitURI = $submit_uri;
+ return $this;
+ }
+
+ public function getSubmitURI() {
+ return $this->submitURI;
+ }
+
+
+
public function render() {
- $viewer = $this->getUser();
+ $viewer = $this->getViewer();
if (!$viewer->isLoggedIn()) {
return null;
}
@@ -34,18 +66,30 @@
require_celerity_resource('global-drag-and-drop-css');
+ $hint_text = $this->getHintText();
+ if (!strlen($hint_text)) {
+ $hint_text = "\xE2\x87\xAA ".pht('Drop Files to Upload');
+ }
+
// Use the configured default view policy. Drag and drop uploads use
// a more restrictive view policy if we don't specify a policy explicitly,
// as the more restrictive policy is correct for most drop targets (like
// Pholio uploads and Remarkup text areas).
- $view_policy = PhabricatorFile::initializeNewFile()->getViewPolicy();
+ $view_policy = $this->getViewPolicy();
+ if ($view_policy === null) {
+ $view_policy = PhabricatorFile::initializeNewFile()->getViewPolicy();
+ }
+
+ $submit_uri = $this->getSubmitURI();
+ $done_uri = '/file/query/authored/';
Javelin::initBehavior('global-drag-and-drop', array(
'ifSupported' => $this->showIfSupportedID,
'instructions' => $instructions_id,
'uploadURI' => '/file/dropupload/',
- 'browseURI' => '/file/query/authored/',
+ 'submitURI' => $submit_uri,
+ 'browseURI' => $done_uri,
'viewPolicy' => $view_policy,
'chunkThreshold' => PhabricatorFileStorageEngine::getChunkThreshold(),
));
@@ -57,6 +101,6 @@
'class' => 'phabricator-global-upload-instructions',
'style' => 'display: none;',
),
- "\xE2\x87\xAA ".pht('Drop Files to Upload'));
+ $hint_text);
}
}
diff --git a/src/applications/search/view/PhabricatorApplicationSearchResultView.php b/src/applications/search/view/PhabricatorApplicationSearchResultView.php
--- a/src/applications/search/view/PhabricatorApplicationSearchResultView.php
+++ b/src/applications/search/view/PhabricatorApplicationSearchResultView.php
@@ -94,6 +94,4 @@
return $this->header;
}
-
-
}
diff --git a/webroot/rsrc/js/core/behavior-global-drag-and-drop.js b/webroot/rsrc/js/core/behavior-global-drag-and-drop.js
--- a/webroot/rsrc/js/core/behavior-global-drag-and-drop.js
+++ b/webroot/rsrc/js/core/behavior-global-drag-and-drop.js
@@ -70,7 +70,14 @@
// If whatever the user dropped in has finished uploading, send them to
// their uploads.
var uri;
- uri = JX.$U(config.browseURI);
+ var is_submit = !!config.submitURI;
+
+ if (is_submit) {
+ uri = JX.$U(config.submitURI);
+ } else {
+ uri = JX.$U(config.browseURI);
+ }
+
var ids = [];
for (var ii = 0; ii < statics.files.length; ii++) {
ids.push(statics.files[ii].getID());
@@ -79,7 +86,12 @@
statics.files = [];
- uri.go();
+ if (is_submit) {
+ new JX.Workflow(uri)
+ .start();
+ } else {
+ uri.go();
+ }
}
});

File Metadata

Mime Type
text/plain
Expires
Sat, Nov 16, 4:33 PM (1 d, 20 h ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6721679
Default Alt Text
D16722.diff (15 KB)

Event Timeline