Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F14311697
D15202.id36699.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
29 KB
Referenced Files
None
Subscribers
None
D15202.id36699.diff
View Options
diff --git a/resources/builtin/image-526x526.png b/resources/builtin/image-526x526.png
new file mode 100644
index 0000000000000000000000000000000000000000..853539d21aec0c1af03257e10ceeab52a50bcc0b
GIT binary patch
literal 2435
zc%17D@N?(olHy`uVBq!ia0y~yVB!N|4kn;T{7s=eASGGi8c`CQpH@<ySd_}(n3A8A
zs^FQMn4TJxnwU~qcrw+7fq_%i)5S5Q;?|qH{@KEn5(f$=`($w}ZC%FAwf6QQxvqKT
z-!FXDtN!%h^@qIbFIV>Ur(SQadTTvFZr20(BV`AhCuwx}3MyviWbNkvxzTyTzlqz}
z=hoO=Ffg8bCh<T`?I-Wsmwws*k7H_hoci(W<vaX&EDY{dKVQ|}jAeL`62#aL!k{3^
z;K9m(!eqcMfvya~#G)Uc1W7iII%Q-yC65SWYO;;CHwa#Q|NZ~J*XQ%L|Ni;;`RDkx
zK`YOkJ^T0DZ~4e)@`6E(u7VR^lvtfUeOi2K*VL&~<JOzo*}c1`BpNVdWzzcx4;DnN
z-4?aBXlIPp)N^HX4<A0f<J_M=H8yp>R75>kMZEW%THg5J;$nCAYf5tqHfbDr^eD;d
zXZAVvl@0IxD-+7fz9lH^z2k0n>0|KxdpTzNpP5YH`mrx~;`WDcZ*RA@w%%xMYHDh1
zJh}e6MW(<+F1L5_z0n6UmMLwCTH7yge~m3k`B>}2kB=-2TRm8V7?1k9?z!VGv~Bx#
z?WtZ|4mn$HzYVsYsH6yTNz6aBps4BR!gVg~FnIIw^78EL?D#Lr`<Z}Jm8&|A>ztPA
zb=!a6e`QDSjkE1NAD*0?oPK`Z+c$4qbbWx@dnTAz9Z6o2l$e;9l(fiLKzgGzd$8`K
z!sKLS>5A{~Vt3#Dm$dfK@f1l-JI13OexicSK`TrC{`xARdFkM#3D3{ZKhF6wcIAy+
zv)SS6Vs<_e4geb2@ug^fkl~+2^ZSlJKHSb9zrQYa_0>=DjGOlD`}geZ?C9-zPoMAT
z?YUOJ;SQ5q!KxGC8?>E2DbJogJ9Ej2@I8xp_2c$<JpZvlXBn5qKaavsvpqiE&Dy$a
z`}XN-{S`eomC7C`{G0MeDPdIu)2Z~Phn|nP%irCZId9&(605z9H#+WGNK|@!+_0v1
zB~zDuXisnN(yd*}=T}~Ty*>Ya-+Mh>-J|bby?XWVzmm|$m|$Soy2>v-{j~b~yWHGd
zS#!xHPv1qYomTe#{(kw*uKO}R{`mNKwt4=pUSMe2h-xyc@97sg{{8#+%g-~CmFG@7
z*Z(}~nw!>wA1gZ^F1Y`Geod6fqhr0&8#nIWJ$sg+P4Nzpz8D_%yLsQQd~GW^^x?_F
z^OB0920}^<d*kw}tAF!&U%uE`vCcGi2~(Gi&ywTp{Bm=i=Vvefn)?{!G_yV53byS$
zV(X%{U`E^jprb$6D@y=P4EPoKy1Q!X`SonTq!GCK>brY;XV=YmHz(M&N3GZGa6)5<
z!@`i&$@c$0y>921*GsXqI=yM-%41JYo0^NQY<RTd`s?fK{#JZ_b(MQ()EVK6oqwj+
zH-tDCF6(;r<jIoX4CxQP3sWP*W6#$lW_av2jyh#zIHfh32xIQg(%Bccuj;)UL&2Q?
cED{W|hi4jFPcfeZY*jIMy85}Sb4q9e0AAhZX#fBK
literal 0
Hc$@<O00001
diff --git a/resources/celerity/map.php b/resources/celerity/map.php
--- a/resources/celerity/map.php
+++ b/resources/celerity/map.php
@@ -8,10 +8,10 @@
return array(
'names' => array(
'core.pkg.css' => 'a7d4cf8f',
- 'core.pkg.js' => 'ef5e33db',
+ 'core.pkg.js' => '808ae845',
'darkconsole.pkg.js' => 'e7393ebb',
'differential.pkg.css' => '2de124c9',
- 'differential.pkg.js' => '5c2ba922',
+ 'differential.pkg.js' => '6b42b4bc',
'diffusion.pkg.css' => 'f45955ed',
'diffusion.pkg.js' => '3a9a8bfa',
'maniphest.pkg.css' => '4845691a',
@@ -155,7 +155,7 @@
'rsrc/css/phui/phui-timeline-view.css' => '2efceff8',
'rsrc/css/phui/phui-two-column-view.css' => 'c75bfc5b',
'rsrc/css/phui/workboards/phui-workboard.css' => 'b07a5524',
- 'rsrc/css/phui/workboards/phui-workcard.css' => 'adf34f58',
+ 'rsrc/css/phui/workboards/phui-workcard.css' => 'a869098a',
'rsrc/css/phui/workboards/phui-workpanel.css' => 'e1bd8d04',
'rsrc/css/sprite-login.css' => '60e8560e',
'rsrc/css/sprite-menu.css' => '9dd65b92',
@@ -414,7 +414,7 @@
'rsrc/js/application/phortune/phortune-credit-card-form.js' => '2290aeef',
'rsrc/js/application/policy/behavior-policy-control.js' => 'd0c516d5',
'rsrc/js/application/policy/behavior-policy-rule-editor.js' => '5e9f347c',
- 'rsrc/js/application/projects/behavior-project-boards.js' => '48470f95',
+ 'rsrc/js/application/projects/behavior-project-boards.js' => '5191522f',
'rsrc/js/application/projects/behavior-project-create.js' => '065227cc',
'rsrc/js/application/projects/behavior-reorder-columns.js' => 'e1d25dfb',
'rsrc/js/application/releeph/releeph-preview-branch.js' => 'b2b4fbaf',
@@ -446,9 +446,9 @@
'rsrc/js/application/uiexample/gesture-example.js' => '558829c2',
'rsrc/js/application/uiexample/notification-example.js' => '8ce821c5',
'rsrc/js/core/Busy.js' => '59a7976a',
- 'rsrc/js/core/DragAndDropFileUpload.js' => 'ad10aeac',
+ 'rsrc/js/core/DragAndDropFileUpload.js' => 'da044194',
'rsrc/js/core/DraggableList.js' => '8905523d',
- 'rsrc/js/core/FileUpload.js' => '477359c8',
+ 'rsrc/js/core/FileUpload.js' => '680ea2c8',
'rsrc/js/core/Hovercard.js' => '1bd28176',
'rsrc/js/core/KeyboardShortcut.js' => '1ae869f2',
'rsrc/js/core/KeyboardShortcutManager.js' => 'c1700f6f',
@@ -654,7 +654,7 @@
'javelin-behavior-phui-profile-menu' => '12884df9',
'javelin-behavior-policy-control' => 'd0c516d5',
'javelin-behavior-policy-rule-editor' => '5e9f347c',
- 'javelin-behavior-project-boards' => '48470f95',
+ 'javelin-behavior-project-boards' => '5191522f',
'javelin-behavior-project-create' => '065227cc',
'javelin-behavior-quicksand-blacklist' => '7927a7d3',
'javelin-behavior-recurring-edit' => '5f1c4d5f',
@@ -741,11 +741,11 @@
'phabricator-core-css' => '5b3563c8',
'phabricator-countdown-css' => 'e7544472',
'phabricator-dashboard-css' => 'eb458607',
- 'phabricator-drag-and-drop-file-upload' => 'ad10aeac',
+ 'phabricator-drag-and-drop-file-upload' => 'da044194',
'phabricator-draggable-list' => '8905523d',
'phabricator-fatal-config-template-css' => '8e6c6fcd',
'phabricator-feed-css' => 'ecd4ec57',
- 'phabricator-file-upload' => '477359c8',
+ 'phabricator-file-upload' => '680ea2c8',
'phabricator-filetree-view-css' => 'fccf9f82',
'phabricator-flag-css' => '5337623f',
'phabricator-keyboard-shortcut' => '1ae869f2',
@@ -832,7 +832,7 @@
'phui-timeline-view-css' => '2efceff8',
'phui-two-column-view-css' => 'c75bfc5b',
'phui-workboard-view-css' => 'b07a5524',
- 'phui-workcard-view-css' => 'adf34f58',
+ 'phui-workcard-view-css' => 'a869098a',
'phui-workpanel-view-css' => 'e1bd8d04',
'phuix-action-list-view' => 'b5c256b8',
'phuix-action-view' => '8cf6d262',
@@ -1133,11 +1133,6 @@
'javelin-dom',
'javelin-workflow',
),
- '477359c8' => array(
- 'javelin-install',
- 'javelin-dom',
- 'phabricator-notification',
- ),
47830651 => array(
'javelin-behavior',
'javelin-dom',
@@ -1154,15 +1149,6 @@
'javelin-dom',
'javelin-workflow',
),
- '48470f95' => array(
- 'javelin-behavior',
- 'javelin-dom',
- 'javelin-util',
- 'javelin-vector',
- 'javelin-stratcom',
- 'javelin-workflow',
- 'phabricator-draggable-list',
- ),
'49b73b36' => array(
'javelin-behavior',
'javelin-dom',
@@ -1204,6 +1190,16 @@
'javelin-typeahead-source',
'javelin-util',
),
+ '5191522f' => array(
+ 'javelin-behavior',
+ 'javelin-dom',
+ 'javelin-util',
+ 'javelin-vector',
+ 'javelin-stratcom',
+ 'javelin-workflow',
+ 'phabricator-draggable-list',
+ 'phabricator-drag-and-drop-file-upload',
+ ),
'519705ea' => array(
'javelin-install',
'javelin-dom',
@@ -1331,6 +1327,11 @@
'javelin-request',
'javelin-workflow',
),
+ '680ea2c8' => array(
+ 'javelin-install',
+ 'javelin-dom',
+ 'phabricator-notification',
+ ),
'6882e80a' => array(
'javelin-dom',
),
@@ -1674,14 +1675,6 @@
'javelin-util',
'phabricator-busy',
),
- 'ad10aeac' => array(
- 'javelin-install',
- 'javelin-util',
- 'javelin-request',
- 'javelin-dom',
- 'javelin-uri',
- 'phabricator-file-upload',
- ),
'b064af76' => array(
'javelin-behavior',
'javelin-stratcom',
@@ -1897,6 +1890,14 @@
'javelin-util',
'phabricator-shaped-request',
),
+ 'da044194' => array(
+ 'javelin-install',
+ 'javelin-util',
+ 'javelin-request',
+ 'javelin-dom',
+ 'javelin-uri',
+ 'phabricator-file-upload',
+ ),
'dbbf48b6' => array(
'javelin-behavior',
'javelin-stratcom',
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
@@ -2880,6 +2880,7 @@
'PhabricatorProjectConfiguredCustomField' => 'applications/project/customfield/PhabricatorProjectConfiguredCustomField.php',
'PhabricatorProjectController' => 'applications/project/controller/PhabricatorProjectController.php',
'PhabricatorProjectCoreTestCase' => 'applications/project/__tests__/PhabricatorProjectCoreTestCase.php',
+ 'PhabricatorProjectCoverController' => 'applications/project/controller/PhabricatorProjectCoverController.php',
'PhabricatorProjectCustomField' => 'applications/project/customfield/PhabricatorProjectCustomField.php',
'PhabricatorProjectCustomFieldNumericIndex' => 'applications/project/storage/PhabricatorProjectCustomFieldNumericIndex.php',
'PhabricatorProjectCustomFieldStorage' => 'applications/project/storage/PhabricatorProjectCustomFieldStorage.php',
@@ -7304,6 +7305,7 @@
),
'PhabricatorProjectController' => 'PhabricatorController',
'PhabricatorProjectCoreTestCase' => 'PhabricatorTestCase',
+ 'PhabricatorProjectCoverController' => 'PhabricatorProjectController',
'PhabricatorProjectCustomField' => 'PhabricatorCustomField',
'PhabricatorProjectCustomFieldNumericIndex' => 'PhabricatorCustomFieldNumericIndexStorage',
'PhabricatorProjectCustomFieldStorage' => 'PhabricatorCustomFieldStorage',
diff --git a/src/applications/maniphest/editor/ManiphestTransactionEditor.php b/src/applications/maniphest/editor/ManiphestTransactionEditor.php
--- a/src/applications/maniphest/editor/ManiphestTransactionEditor.php
+++ b/src/applications/maniphest/editor/ManiphestTransactionEditor.php
@@ -28,6 +28,7 @@
$types[] = ManiphestTransaction::TYPE_UNBLOCK;
$types[] = ManiphestTransaction::TYPE_PARENT;
$types[] = ManiphestTransaction::TYPE_COLUMN;
+ $types[] = ManiphestTransaction::TYPE_COVER_IMAGE;
$types[] = PhabricatorTransactions::TYPE_VIEW_POLICY;
$types[] = PhabricatorTransactions::TYPE_EDIT_POLICY;
@@ -66,6 +67,8 @@
return $xaction->getOldValue();
case ManiphestTransaction::TYPE_SUBPRIORITY:
return $object->getSubpriority();
+ case ManiphestTransaction::TYPE_COVER_IMAGE:
+ return $object->getCoverImageFilePHID();
case ManiphestTransaction::TYPE_MERGED_INTO:
case ManiphestTransaction::TYPE_MERGED_FROM:
return null;
@@ -92,6 +95,7 @@
case ManiphestTransaction::TYPE_MERGED_INTO:
case ManiphestTransaction::TYPE_MERGED_FROM:
case ManiphestTransaction::TYPE_UNBLOCK:
+ case ManiphestTransaction::TYPE_COVER_IMAGE:
return $xaction->getNewValue();
case ManiphestTransaction::TYPE_PARENT:
case ManiphestTransaction::TYPE_COLUMN:
@@ -161,6 +165,32 @@
case ManiphestTransaction::TYPE_MERGED_INTO:
$object->setStatus(ManiphestTaskStatus::getDuplicateStatus());
return;
+ case ManiphestTransaction::TYPE_COVER_IMAGE:
+ $file_phid = $xaction->getNewValue();
+
+ if ($file_phid) {
+ $file = id(new PhabricatorFileQuery())
+ ->setViewer($this->getActor())
+ ->withPHIDs(array($file_phid))
+ ->executeOne();
+ } else {
+ $file = null;
+ }
+
+ if (!$file || !$file->isTransformableImage()) {
+ $object->setProperty('cover.filePHID', null);
+ $object->setProperty('cover.thumbnailPHID', null);
+ return;
+ }
+
+ $xform_key = PhabricatorFileThumbnailTransform::TRANSFORM_WORKCARD;
+
+ $xform = PhabricatorFileTransform::getTransformByKey($xform_key)
+ ->executeTransform($file);
+
+ $object->setProperty('cover.filePHID', $file->getPHID());
+ $object->setProperty('cover.thumbnailPHID', $xform->getPHID());
+ return;
case ManiphestTransaction::TYPE_MERGED_FROM:
case ManiphestTransaction::TYPE_PARENT:
case ManiphestTransaction::TYPE_COLUMN:
@@ -819,6 +849,41 @@
}
}
break;
+ case ManiphestTransaction::TYPE_COVER_IMAGE:
+ foreach ($xactions as $xaction) {
+ $old = $xaction->getOldValue();
+ $new = $xaction->getNewValue();
+ if (!$new) {
+ continue;
+ }
+
+ if ($new === $old) {
+ continue;
+ }
+
+ $file = id(new PhabricatorFileQuery())
+ ->setViewer($this->getActor())
+ ->withPHIDs(array($new))
+ ->executeOne();
+ if (!$file) {
+ $errors[] = new PhabricatorApplicationTransactionValidationError(
+ $type,
+ pht('Invalid'),
+ pht('File "%s" is not valid.', $new),
+ $xaction);
+ continue;
+ }
+
+ if (!$file->isTransformableImage()) {
+ $errors[] = new PhabricatorApplicationTransactionValidationError(
+ $type,
+ pht('Invalid'),
+ pht('File "%s" is not a valid image file.', $new),
+ $xaction);
+ continue;
+ }
+ }
+ break;
}
return $errors;
@@ -941,5 +1006,19 @@
->executeOne();
}
+ protected function extractFilePHIDsFromCustomTransaction(
+ PhabricatorLiskDAO $object,
+ PhabricatorApplicationTransaction $xaction) {
+ $phids = parent::extractFilePHIDsFromCustomTransaction($object, $xaction);
+
+ switch ($xaction->getTransactionType()) {
+ case ManiphestTransaction::TYPE_COVER_IMAGE:
+ $phids[] = $xaction->getNewValue();
+ break;
+ }
+
+ return $phids;
+ }
+
}
diff --git a/src/applications/maniphest/storage/ManiphestTask.php b/src/applications/maniphest/storage/ManiphestTask.php
--- a/src/applications/maniphest/storage/ManiphestTask.php
+++ b/src/applications/maniphest/storage/ManiphestTask.php
@@ -226,6 +226,10 @@
return idx($this->properties, $key, $default);
}
+ public function getCoverImageFilePHID() {
+ return idx($this->properties, 'cover.filePHID');
+ }
+
public function getCoverImageThumbnailPHID() {
return idx($this->properties, 'cover.thumbnailPHID');
}
diff --git a/src/applications/maniphest/storage/ManiphestTransaction.php b/src/applications/maniphest/storage/ManiphestTransaction.php
--- a/src/applications/maniphest/storage/ManiphestTransaction.php
+++ b/src/applications/maniphest/storage/ManiphestTransaction.php
@@ -16,6 +16,7 @@
const TYPE_UNBLOCK = 'unblock';
const TYPE_PARENT = 'parent';
const TYPE_COLUMN = 'column';
+ const TYPE_COVER_IMAGE = 'cover-image';
// NOTE: this type is deprecated. Keep it around for legacy installs
// so any transactions render correctly.
@@ -162,6 +163,9 @@
sort($new_cols);
return ($old_cols === $new_cols);
+ case self::TYPE_COVER_IMAGE:
+ // At least for now, don't show these.
+ return true;
}
return parent::shouldHide();
diff --git a/src/applications/project/application/PhabricatorProjectApplication.php b/src/applications/project/application/PhabricatorProjectApplication.php
--- a/src/applications/project/application/PhabricatorProjectApplication.php
+++ b/src/applications/project/application/PhabricatorProjectApplication.php
@@ -72,6 +72,7 @@
'(?:query/(?P<queryKey>[^/]+)/)?'
=> 'PhabricatorProjectBoardViewController',
'move/(?P<id>[1-9]\d*)/' => 'PhabricatorProjectMoveController',
+ 'cover/' => 'PhabricatorProjectCoverController',
'board/(?P<projectID>[1-9]\d*)/' => array(
'edit/(?:(?P<id>\d+)/)?'
=> 'PhabricatorProjectColumnEditController',
diff --git a/src/applications/project/controller/PhabricatorProjectBoardViewController.php b/src/applications/project/controller/PhabricatorProjectBoardViewController.php
--- a/src/applications/project/controller/PhabricatorProjectBoardViewController.php
+++ b/src/applications/project/controller/PhabricatorProjectBoardViewController.php
@@ -219,6 +219,9 @@
'projectPHID' => $project->getPHID(),
'moveURI' => $this->getApplicationURI('move/'.$project->getID().'/'),
'createURI' => $this->getCreateURI(),
+ 'uploadURI' => '/file/dropupload/',
+ 'coverURI' => $this->getApplicationURI('cover/'),
+ 'chunkThreshold' => PhabricatorFileStorageEngine::getChunkThreshold(),
'order' => $this->sortKey,
);
$this->initBehavior(
diff --git a/src/applications/project/controller/PhabricatorProjectController.php b/src/applications/project/controller/PhabricatorProjectController.php
--- a/src/applications/project/controller/PhabricatorProjectController.php
+++ b/src/applications/project/controller/PhabricatorProjectController.php
@@ -147,4 +147,53 @@
return $this;
}
+ protected function newCardResponse($board_phid, $object_phid) {
+ $viewer = $this->getViewer();
+
+ $project = id(new PhabricatorProjectQuery())
+ ->setViewer($viewer)
+ ->withPHIDs(array($board_phid))
+ ->executeOne();
+ if (!$project) {
+ return new Aphront404Response();
+ }
+
+ // Reload the object so it reflects edits which have been applied.
+ $object = id(new ManiphestTaskQuery())
+ ->setViewer($viewer)
+ ->withPHIDs(array($object_phid))
+ ->needProjectPHIDs(true)
+ ->executeOne();
+ if (!$object) {
+ return new Aphront404Response();
+ }
+
+ $except_phids = array($board_phid);
+ if ($project->getHasSubprojects() || $project->getHasMilestones()) {
+ $descendants = id(new PhabricatorProjectQuery())
+ ->setViewer($viewer)
+ ->withAncestorProjectPHIDs($except_phids)
+ ->execute();
+ foreach ($descendants as $descendant) {
+ $except_phids[] = $descendant->getPHID();
+ }
+ }
+
+ $rendering_engine = id(new PhabricatorBoardRenderingEngine())
+ ->setViewer($viewer)
+ ->setObjects(array($object))
+ ->setExcludedProjectPHIDs($except_phids);
+
+ $card = $rendering_engine->renderCard($object->getPHID());
+
+ $item = $card->getItem();
+ $item->addClass('phui-workcard');
+
+ return id(new AphrontAjaxResponse())
+ ->setContent(
+ array(
+ 'task' => $item,
+ ));
+ }
+
}
diff --git a/src/applications/project/controller/PhabricatorProjectCoverController.php b/src/applications/project/controller/PhabricatorProjectCoverController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/project/controller/PhabricatorProjectCoverController.php
@@ -0,0 +1,53 @@
+<?php
+
+final class PhabricatorProjectCoverController
+ extends PhabricatorProjectController {
+
+ public function handleRequest(AphrontRequest $request) {
+ $viewer = $request->getViewer();
+
+ $request->validateCSRF();
+
+ $board_phid = $request->getStr('boardPHID');
+ $object_phid = $request->getStr('objectPHID');
+ $file_phid = $request->getStr('filePHID');
+
+ $object = id(new ManiphestTaskQuery())
+ ->setViewer($viewer)
+ ->withPHIDs(array($object_phid))
+ ->requireCapabilities(
+ array(
+ PhabricatorPolicyCapability::CAN_VIEW,
+ PhabricatorPolicyCapability::CAN_EDIT,
+ ))
+ ->executeOne();
+ if (!$object) {
+ return new Aphront404Response();
+ }
+
+ $file = id(new PhabricatorFileQuery())
+ ->setViewer($viewer)
+ ->withPHIDs(array($file_phid))
+ ->executeOne();
+ if (!$file) {
+ return new Aphront404Response();
+ }
+
+ $xactions = array();
+
+ $xactions[] = id(new ManiphestTransaction())
+ ->setTransactionType(ManiphestTransaction::TYPE_COVER_IMAGE)
+ ->setNewValue($file->getPHID());
+
+ $editor = id(new ManiphestTransactionEditor())
+ ->setActor($viewer)
+ ->setContinueOnMissingFields(true)
+ ->setContinueOnNoEffect(true)
+ ->setContentSourceFromRequest($request);
+
+ $editor->applyTransactions($object, $xactions);
+
+ return $this->newCardResponse($board_phid, $object_phid);
+ }
+
+}
diff --git a/src/applications/project/controller/PhabricatorProjectMoveController.php b/src/applications/project/controller/PhabricatorProjectMoveController.php
--- a/src/applications/project/controller/PhabricatorProjectMoveController.php
+++ b/src/applications/project/controller/PhabricatorProjectMoveController.php
@@ -7,13 +7,14 @@
$viewer = $request->getViewer();
$id = $request->getURIData('id');
+ $request->validateCSRF();
+
$column_phid = $request->getStr('columnPHID');
$object_phid = $request->getStr('objectPHID');
$after_phid = $request->getStr('afterPHID');
$before_phid = $request->getStr('beforePHID');
$order = $request->getStr('order', PhabricatorProjectColumn::DEFAULT_ORDER);
-
$project = id(new PhabricatorProjectQuery())
->setViewer($viewer)
->requireCapabilities(
@@ -175,39 +176,7 @@
$editor->applyTransactions($object, $xactions);
- // Reload the object so it reflects edits which have been applied.
- $object = id(new ManiphestTaskQuery())
- ->setViewer($viewer)
- ->withPHIDs(array($object_phid))
- ->needProjectPHIDs(true)
- ->executeOne();
-
- $except_phids = array($board_phid);
- if ($project->getHasSubprojects() || $project->getHasMilestones()) {
- $descendants = id(new PhabricatorProjectQuery())
- ->setViewer($viewer)
- ->withAncestorProjectPHIDs($except_phids)
- ->execute();
- foreach ($descendants as $descendant) {
- $except_phids[] = $descendant->getPHID();
- }
- }
-
- $rendering_engine = id(new PhabricatorBoardRenderingEngine())
- ->setViewer($viewer)
- ->setObjects(array($object))
- ->setExcludedProjectPHIDs($except_phids);
-
- $card = $rendering_engine->renderCard($object->getPHID());
-
- $item = $card->getItem();
- $item->addClass('phui-workcard');
-
- return id(new AphrontAjaxResponse())
- ->setContent(
- array(
- 'task' => $item,
- ));
+ return $this->newCardResponse($board_phid, $object_phid);
}
}
diff --git a/webroot/rsrc/css/phui/workboards/phui-workcard.css b/webroot/rsrc/css/phui/workboards/phui-workcard.css
--- a/webroot/rsrc/css/phui/workboards/phui-workcard.css
+++ b/webroot/rsrc/css/phui/workboards/phui-workcard.css
@@ -106,6 +106,10 @@
width: 263px;
}
+.phui-workcard.phui-object-item.phui-workcard-upload-target {
+ background-color: {$sh-greenbackground};
+}
+
/* - Draggable Colors --------------------------------------------------------*/
diff --git a/webroot/rsrc/js/application/projects/behavior-project-boards.js b/webroot/rsrc/js/application/projects/behavior-project-boards.js
--- a/webroot/rsrc/js/application/projects/behavior-project-boards.js
+++ b/webroot/rsrc/js/application/projects/behavior-project-boards.js
@@ -7,6 +7,7 @@
* javelin-stratcom
* javelin-workflow
* phabricator-draggable-list
+ * phabricator-drag-and-drop-file-upload
*/
JX.behavior('project-boards', function(config, statics) {
@@ -348,6 +349,39 @@
init_board();
}
});
+
+ if (JX.PhabricatorDragAndDropFileUpload.isSupported()) {
+ var drop = new JX.PhabricatorDragAndDropFileUpload('project-card')
+ .setURI(config.uploadURI)
+ .setChunkThreshold(config.chunkThreshold);
+
+ drop.listen('didBeginDrag', function(node) {
+ JX.DOM.alterClass(node, 'phui-workcard-upload-target', true);
+ });
+
+ drop.listen('didEndDrag', function(node) {
+ JX.DOM.alterClass(node, 'phui-workcard-upload-target', false);
+ });
+
+ drop.listen('didUpload', function(file) {
+ var node = file.getTargetNode();
+
+ var data = {
+ boardPHID: statics.projectPHID,
+ objectPHID: JX.Stratcom.getData(node).objectPHID,
+ filePHID: file.getPHID()
+ };
+
+ new JX.Workflow(config.coverURI, data)
+ .setHandler(function(r) {
+ JX.DOM.replace(node, JX.$H(r.task));
+ })
+ .start();
+ });
+
+ drop.start();
+ }
+
return true;
}
diff --git a/webroot/rsrc/js/core/DragAndDropFileUpload.js b/webroot/rsrc/js/core/DragAndDropFileUpload.js
--- a/webroot/rsrc/js/core/DragAndDropFileUpload.js
+++ b/webroot/rsrc/js/core/DragAndDropFileUpload.js
@@ -11,8 +11,12 @@
JX.install('PhabricatorDragAndDropFileUpload', {
- construct : function(node) {
- this._node = node;
+ construct : function(target) {
+ if (JX.DOM.isNode(target)) {
+ this._node = target;
+ } else {
+ this._sigil = target;
+ }
},
events : [
@@ -39,6 +43,7 @@
members : {
_node : null,
+ _sigil: null,
_depth : 0,
_isEnabled: false,
@@ -53,18 +58,21 @@
_updateDepth : function(delta) {
if (this._depth === 0 && delta > 0) {
- this.invoke('didBeginDrag');
+ this.invoke('didBeginDrag', this._getTarget());
}
this._depth += delta;
if (this._depth === 0 && delta < 0) {
- this.invoke('didEndDrag');
+ this.invoke('didEndDrag', this._getTarget());
}
},
- start : function() {
+ _getTarget: function() {
+ return this._target || this._node;
+ },
+ start : function() {
// TODO: move this to JX.DOM.contains()?
function contains(container, child) {
@@ -80,87 +88,87 @@
// Firefox has some issues sometimes; implement this click handler so
// the user can recover. See T5188.
- JX.DOM.listen(
- this._node,
- 'click',
- null,
- JX.bind(this, function (e) {
- if (!this.getIsEnabled()) {
- return;
- }
- if (this._depth) {
- e.kill();
- // Force depth to 0.
- this._updateDepth(-this._depth);
- }
- }));
+ var on_click = JX.bind(this, function (e) {
+ if (!this.getIsEnabled()) {
+ return;
+ }
+
+ if (this._depth) {
+ e.kill();
+ // Force depth to 0.
+ this._updateDepth(-this._depth);
+ }
+ });
// We track depth so that the _node may have children inside of it and
// not become unselected when they are dragged over.
- JX.DOM.listen(
- this._node,
- 'dragenter',
- null,
- JX.bind(this, function(e) {
- if (!this.getIsEnabled()) {
- return;
- }
+ var on_dragenter = JX.bind(this, function(e) {
+ if (!this.getIsEnabled()) {
+ return;
+ }
- if (contains(this._node, e.getTarget())) {
- this._updateDepth(1);
- }
- }));
-
- JX.DOM.listen(
- this._node,
- 'dragleave',
- null,
- JX.bind(this, function(e) {
- if (!this.getIsEnabled()) {
- return;
- }
+ if (!this._node && !this._depth) {
+ this._target = e.getNode(this._sigil);
+ }
- if (contains(this._node, e.getTarget())) {
- this._updateDepth(-1);
- }
- }));
-
- JX.DOM.listen(
- this._node,
- 'dragover',
- null,
- JX.bind(this, function(e) {
- if (!this.getIsEnabled()) {
- return;
- }
+ if (contains(this._getTarget(), e.getTarget())) {
+ this._updateDepth(1);
+ }
+ });
- // NOTE: We must set this, or Chrome refuses to drop files from the
- // download shelf.
- e.getRawEvent().dataTransfer.dropEffect = 'copy';
- e.kill();
- }));
-
- JX.DOM.listen(
- this._node,
- 'drop',
- null,
- JX.bind(this, function(e) {
- if (!this.getIsEnabled()) {
- return;
- }
+ var on_dragleave = JX.bind(this, function(e) {
+ if (!this.getIsEnabled()) {
+ return;
+ }
- e.kill();
+ if (contains(this._getTarget(), e.getTarget())) {
+ this._updateDepth(-1);
+ }
+ });
- var files = e.getRawEvent().dataTransfer.files;
- for (var ii = 0; ii < files.length; ii++) {
- this._sendRequest(files[ii]);
- }
+ var on_dragover = JX.bind(this, function(e) {
+ if (!this.getIsEnabled()) {
+ return;
+ }
- // Force depth to 0.
- this._updateDepth(-this._depth);
- }));
+ // NOTE: We must set this, or Chrome refuses to drop files from the
+ // download shelf.
+ e.getRawEvent().dataTransfer.dropEffect = 'copy';
+ e.kill();
+ });
+
+ var on_drop = JX.bind(this, function(e) {
+ if (!this.getIsEnabled()) {
+ return;
+ }
+
+ e.kill();
+
+ var files = e.getRawEvent().dataTransfer.files;
+ for (var ii = 0; ii < files.length; ii++) {
+ this._sendRequest(files[ii]);
+ }
+
+ // Force depth to 0.
+ this._updateDepth(-this._depth);
+ });
+
+ if (this._node) {
+ JX.DOM.listen(this._node, 'click', null, on_click);
+ JX.DOM.listen(this._node, 'dragenter', null, on_dragenter);
+ JX.DOM.listen(this._node, 'dragleave', null, on_dragleave);
+ JX.DOM.listen(this._node, 'dragover', null, on_dragover);
+ JX.DOM.listen(this._node, 'drop', null, on_drop);
+ } else {
+ JX.Stratcom.listen('click', this._sigil, on_click);
+ JX.Stratcom.listen('dragenter', this._sigil, on_dragenter);
+ JX.Stratcom.listen('dragleave', this._sigil, on_dragleave);
+ JX.Stratcom.listen('dragover', this._sigil, on_dragover);
+ JX.Stratcom.listen('drop', this._sigil, on_drop);
+ }
- if (JX.PhabricatorDragAndDropFileUpload.isPasteSupported()) {
+ if (JX.PhabricatorDragAndDropFileUpload.isPasteSupported() &&
+ this._node) {
JX.DOM.listen(
this._node,
'paste',
@@ -399,6 +407,7 @@
.setURI(r.uri)
.setMarkup(r.html)
.setStatus('done')
+ .setTargetNode(this._getTarget())
.update();
this.invoke('didUpload', file);
diff --git a/webroot/rsrc/js/core/FileUpload.js b/webroot/rsrc/js/core/FileUpload.js
--- a/webroot/rsrc/js/core/FileUpload.js
+++ b/webroot/rsrc/js/core/FileUpload.js
@@ -23,6 +23,7 @@
URI: null,
status: null,
markup: null,
+ targetNode: null,
error: null
},
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, Dec 19, 2:42 AM (18 h, 58 m)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6905747
Default Alt Text
D15202.id36699.diff (29 KB)
Attached To
Mode
D15202: Support drag-and-drop to set cover images on workboard cards
Attached
Detach File
Event Timeline
Log In to Comment