mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-15 10:00:55 +01:00
(stable) Promote 2017 Week 21
This commit is contained in:
commit
c7eae8f031
175 changed files with 3504 additions and 1757 deletions
|
@ -1,30 +1,3 @@
|
|||
<?php
|
||||
|
||||
// Destroy duplicate drafts before storage adjustment adds a unique key to this
|
||||
// table. See T1191. We retain the newest draft.
|
||||
|
||||
// (We can't easily do this in a single SQL statement because MySQL won't let us
|
||||
// modify a table that's joined in a subquery.)
|
||||
|
||||
$table = new DifferentialDraft();
|
||||
$conn_w = $table->establishConnection('w');
|
||||
|
||||
$duplicates = queryfx_all(
|
||||
$conn_w,
|
||||
'SELECT DISTINCT u.id id FROM %T u
|
||||
JOIN %T v
|
||||
ON u.objectPHID = v.objectPHID
|
||||
AND u.authorPHID = v.authorPHID
|
||||
AND u.draftKey = v.draftKey
|
||||
AND u.id < v.id',
|
||||
$table->getTableName(),
|
||||
$table->getTableName());
|
||||
|
||||
$duplicates = ipull($duplicates, 'id');
|
||||
foreach (PhabricatorLiskDAO::chunkSQL($duplicates) as $chunk) {
|
||||
queryfx(
|
||||
$conn_w,
|
||||
'DELETE FROM %T WHERE id IN (%Q)',
|
||||
$table->getTableName(),
|
||||
$chunk);
|
||||
}
|
||||
// This table has been removed; see T12104 for details.
|
||||
|
|
2
resources/sql/autopatches/20170522.nuance.01.itemkey.sql
Normal file
2
resources/sql/autopatches/20170522.nuance.01.itemkey.sql
Normal file
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE {$NAMESPACE}_nuance.nuance_item
|
||||
MODIFY itemKey VARCHAR(64) COLLATE {$COLLATE_TEXT};
|
8
resources/sql/autopatches/20170524.nuance.01.command.sql
Normal file
8
resources/sql/autopatches/20170524.nuance.01.command.sql
Normal file
|
@ -0,0 +1,8 @@
|
|||
ALTER TABLE {$NAMESPACE}_nuance.nuance_itemcommand
|
||||
ADD dateCreated INT UNSIGNED NOT NULL;
|
||||
|
||||
ALTER TABLE {$NAMESPACE}_nuance.nuance_itemcommand
|
||||
ADD dateModified INT UNSIGNED NOT NULL;
|
||||
|
||||
ALTER TABLE {$NAMESPACE}_nuance.nuance_itemcommand
|
||||
ADD queuePHID VARBINARY(64);
|
|
@ -0,0 +1,5 @@
|
|||
ALTER TABLE {$NAMESPACE}_nuance.nuance_itemcommand
|
||||
ADD status VARCHAR(64) NOT NULL;
|
||||
|
||||
UPDATE {$NAMESPACE}_nuance.nuance_itemcommand
|
||||
SET status = 'done' WHERE status = '';
|
|
@ -0,0 +1 @@
|
|||
DROP TABLE {$NAMESPACE}_differential.differential_draft;
|
11
resources/sql/autopatches/20170526.milestones.php
Normal file
11
resources/sql/autopatches/20170526.milestones.php
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
$table = new PhabricatorProject();
|
||||
|
||||
foreach (new LiskMigrationIterator($table) as $project) {
|
||||
PhabricatorSearchWorker::queueDocumentForIndexing(
|
||||
$project->getPHID(),
|
||||
array(
|
||||
'force' => true,
|
||||
));
|
||||
}
|
|
@ -441,7 +441,6 @@ phutil_register_library_map(array(
|
|||
'DifferentialDiffTransactionQuery' => 'applications/differential/query/DifferentialDiffTransactionQuery.php',
|
||||
'DifferentialDiffViewController' => 'applications/differential/controller/DifferentialDiffViewController.php',
|
||||
'DifferentialDoorkeeperRevisionFeedStoryPublisher' => 'applications/differential/doorkeeper/DifferentialDoorkeeperRevisionFeedStoryPublisher.php',
|
||||
'DifferentialDraft' => 'applications/differential/storage/DifferentialDraft.php',
|
||||
'DifferentialExactUserFunctionDatasource' => 'applications/differential/typeahead/DifferentialExactUserFunctionDatasource.php',
|
||||
'DifferentialFieldParseException' => 'applications/differential/exception/DifferentialFieldParseException.php',
|
||||
'DifferentialFieldValidationException' => 'applications/differential/exception/DifferentialFieldValidationException.php',
|
||||
|
@ -661,6 +660,7 @@ phutil_register_library_map(array(
|
|||
'DiffusionCommitHookEngine' => 'applications/diffusion/engine/DiffusionCommitHookEngine.php',
|
||||
'DiffusionCommitHookRejectException' => 'applications/diffusion/exception/DiffusionCommitHookRejectException.php',
|
||||
'DiffusionCommitListController' => 'applications/diffusion/controller/DiffusionCommitListController.php',
|
||||
'DiffusionCommitListView' => 'applications/diffusion/view/DiffusionCommitListView.php',
|
||||
'DiffusionCommitMergeHeraldField' => 'applications/diffusion/herald/DiffusionCommitMergeHeraldField.php',
|
||||
'DiffusionCommitMessageHeraldField' => 'applications/diffusion/herald/DiffusionCommitMessageHeraldField.php',
|
||||
'DiffusionCommitPackageAuditHeraldField' => 'applications/diffusion/herald/DiffusionCommitPackageAuditHeraldField.php',
|
||||
|
@ -1494,6 +1494,7 @@ phutil_register_library_map(array(
|
|||
'ManiphestPointsConfigOptionType' => 'applications/maniphest/config/ManiphestPointsConfigOptionType.php',
|
||||
'ManiphestPriorityConfigOptionType' => 'applications/maniphest/config/ManiphestPriorityConfigOptionType.php',
|
||||
'ManiphestPriorityEmailCommand' => 'applications/maniphest/command/ManiphestPriorityEmailCommand.php',
|
||||
'ManiphestPrioritySearchConduitAPIMethod' => 'applications/maniphest/conduit/ManiphestPrioritySearchConduitAPIMethod.php',
|
||||
'ManiphestProjectNameFulltextEngineExtension' => 'applications/maniphest/engineextension/ManiphestProjectNameFulltextEngineExtension.php',
|
||||
'ManiphestQueryConduitAPIMethod' => 'applications/maniphest/conduit/ManiphestQueryConduitAPIMethod.php',
|
||||
'ManiphestQueryStatusesConduitAPIMethod' => 'applications/maniphest/conduit/ManiphestQueryStatusesConduitAPIMethod.php',
|
||||
|
@ -1600,11 +1601,13 @@ phutil_register_library_map(array(
|
|||
'MultimeterLabel' => 'applications/multimeter/storage/MultimeterLabel.php',
|
||||
'MultimeterSampleController' => 'applications/multimeter/controller/MultimeterSampleController.php',
|
||||
'MultimeterViewer' => 'applications/multimeter/storage/MultimeterViewer.php',
|
||||
'NuanceCommandImplementation' => 'applications/nuance/command/NuanceCommandImplementation.php',
|
||||
'NuanceConduitAPIMethod' => 'applications/nuance/conduit/NuanceConduitAPIMethod.php',
|
||||
'NuanceConsoleController' => 'applications/nuance/controller/NuanceConsoleController.php',
|
||||
'NuanceContentSource' => 'applications/nuance/contentsource/NuanceContentSource.php',
|
||||
'NuanceController' => 'applications/nuance/controller/NuanceController.php',
|
||||
'NuanceDAO' => 'applications/nuance/storage/NuanceDAO.php',
|
||||
'NuanceFormItemType' => 'applications/nuance/item/NuanceFormItemType.php',
|
||||
'NuanceGitHubEventItemType' => 'applications/nuance/item/NuanceGitHubEventItemType.php',
|
||||
'NuanceGitHubImportCursor' => 'applications/nuance/cursor/NuanceGitHubImportCursor.php',
|
||||
'NuanceGitHubIssuesImportCursor' => 'applications/nuance/cursor/NuanceGitHubIssuesImportCursor.php',
|
||||
|
@ -1620,16 +1623,25 @@ phutil_register_library_map(array(
|
|||
'NuanceItemActionController' => 'applications/nuance/controller/NuanceItemActionController.php',
|
||||
'NuanceItemCommand' => 'applications/nuance/storage/NuanceItemCommand.php',
|
||||
'NuanceItemCommandQuery' => 'applications/nuance/query/NuanceItemCommandQuery.php',
|
||||
'NuanceItemCommandSpec' => 'applications/nuance/command/NuanceItemCommandSpec.php',
|
||||
'NuanceItemCommandTransaction' => 'applications/nuance/xaction/NuanceItemCommandTransaction.php',
|
||||
'NuanceItemController' => 'applications/nuance/controller/NuanceItemController.php',
|
||||
'NuanceItemEditor' => 'applications/nuance/editor/NuanceItemEditor.php',
|
||||
'NuanceItemListController' => 'applications/nuance/controller/NuanceItemListController.php',
|
||||
'NuanceItemManageController' => 'applications/nuance/controller/NuanceItemManageController.php',
|
||||
'NuanceItemOwnerTransaction' => 'applications/nuance/xaction/NuanceItemOwnerTransaction.php',
|
||||
'NuanceItemPHIDType' => 'applications/nuance/phid/NuanceItemPHIDType.php',
|
||||
'NuanceItemPropertyTransaction' => 'applications/nuance/xaction/NuanceItemPropertyTransaction.php',
|
||||
'NuanceItemQuery' => 'applications/nuance/query/NuanceItemQuery.php',
|
||||
'NuanceItemQueueTransaction' => 'applications/nuance/xaction/NuanceItemQueueTransaction.php',
|
||||
'NuanceItemRequestorTransaction' => 'applications/nuance/xaction/NuanceItemRequestorTransaction.php',
|
||||
'NuanceItemSearchEngine' => 'applications/nuance/query/NuanceItemSearchEngine.php',
|
||||
'NuanceItemSourceTransaction' => 'applications/nuance/xaction/NuanceItemSourceTransaction.php',
|
||||
'NuanceItemStatusTransaction' => 'applications/nuance/xaction/NuanceItemStatusTransaction.php',
|
||||
'NuanceItemTransaction' => 'applications/nuance/storage/NuanceItemTransaction.php',
|
||||
'NuanceItemTransactionComment' => 'applications/nuance/storage/NuanceItemTransactionComment.php',
|
||||
'NuanceItemTransactionQuery' => 'applications/nuance/query/NuanceItemTransactionQuery.php',
|
||||
'NuanceItemTransactionType' => 'applications/nuance/xaction/NuanceItemTransactionType.php',
|
||||
'NuanceItemType' => 'applications/nuance/item/NuanceItemType.php',
|
||||
'NuanceItemUpdateWorker' => 'applications/nuance/worker/NuanceItemUpdateWorker.php',
|
||||
'NuanceItemViewController' => 'applications/nuance/controller/NuanceItemViewController.php',
|
||||
|
@ -1645,18 +1657,22 @@ phutil_register_library_map(array(
|
|||
'NuanceQueueEditEngine' => 'applications/nuance/editor/NuanceQueueEditEngine.php',
|
||||
'NuanceQueueEditor' => 'applications/nuance/editor/NuanceQueueEditor.php',
|
||||
'NuanceQueueListController' => 'applications/nuance/controller/NuanceQueueListController.php',
|
||||
'NuanceQueueNameTransaction' => 'applications/nuance/xaction/NuanceQueueNameTransaction.php',
|
||||
'NuanceQueuePHIDType' => 'applications/nuance/phid/NuanceQueuePHIDType.php',
|
||||
'NuanceQueueQuery' => 'applications/nuance/query/NuanceQueueQuery.php',
|
||||
'NuanceQueueSearchEngine' => 'applications/nuance/query/NuanceQueueSearchEngine.php',
|
||||
'NuanceQueueTransaction' => 'applications/nuance/storage/NuanceQueueTransaction.php',
|
||||
'NuanceQueueTransactionComment' => 'applications/nuance/storage/NuanceQueueTransactionComment.php',
|
||||
'NuanceQueueTransactionQuery' => 'applications/nuance/query/NuanceQueueTransactionQuery.php',
|
||||
'NuanceQueueTransactionType' => 'applications/nuance/xaction/NuanceQueueTransactionType.php',
|
||||
'NuanceQueueViewController' => 'applications/nuance/controller/NuanceQueueViewController.php',
|
||||
'NuanceQueueWorkController' => 'applications/nuance/controller/NuanceQueueWorkController.php',
|
||||
'NuanceSchemaSpec' => 'applications/nuance/storage/NuanceSchemaSpec.php',
|
||||
'NuanceSource' => 'applications/nuance/storage/NuanceSource.php',
|
||||
'NuanceSourceActionController' => 'applications/nuance/controller/NuanceSourceActionController.php',
|
||||
'NuanceSourceController' => 'applications/nuance/controller/NuanceSourceController.php',
|
||||
'NuanceSourceDefaultEditCapability' => 'applications/nuance/capability/NuanceSourceDefaultEditCapability.php',
|
||||
'NuanceSourceDefaultQueueTransaction' => 'applications/nuance/xaction/NuanceSourceDefaultQueueTransaction.php',
|
||||
'NuanceSourceDefaultViewCapability' => 'applications/nuance/capability/NuanceSourceDefaultViewCapability.php',
|
||||
'NuanceSourceDefinition' => 'applications/nuance/source/NuanceSourceDefinition.php',
|
||||
'NuanceSourceDefinitionTestCase' => 'applications/nuance/source/__tests__/NuanceSourceDefinitionTestCase.php',
|
||||
|
@ -1666,14 +1682,17 @@ phutil_register_library_map(array(
|
|||
'NuanceSourceListController' => 'applications/nuance/controller/NuanceSourceListController.php',
|
||||
'NuanceSourceManageCapability' => 'applications/nuance/capability/NuanceSourceManageCapability.php',
|
||||
'NuanceSourceNameNgrams' => 'applications/nuance/storage/NuanceSourceNameNgrams.php',
|
||||
'NuanceSourceNameTransaction' => 'applications/nuance/xaction/NuanceSourceNameTransaction.php',
|
||||
'NuanceSourcePHIDType' => 'applications/nuance/phid/NuanceSourcePHIDType.php',
|
||||
'NuanceSourceQuery' => 'applications/nuance/query/NuanceSourceQuery.php',
|
||||
'NuanceSourceSearchEngine' => 'applications/nuance/query/NuanceSourceSearchEngine.php',
|
||||
'NuanceSourceTransaction' => 'applications/nuance/storage/NuanceSourceTransaction.php',
|
||||
'NuanceSourceTransactionComment' => 'applications/nuance/storage/NuanceSourceTransactionComment.php',
|
||||
'NuanceSourceTransactionQuery' => 'applications/nuance/query/NuanceSourceTransactionQuery.php',
|
||||
'NuanceSourceTransactionType' => 'applications/nuance/xaction/NuanceSourceTransactionType.php',
|
||||
'NuanceSourceViewController' => 'applications/nuance/controller/NuanceSourceViewController.php',
|
||||
'NuanceTransaction' => 'applications/nuance/storage/NuanceTransaction.php',
|
||||
'NuanceTrashCommand' => 'applications/nuance/command/NuanceTrashCommand.php',
|
||||
'NuanceWorker' => 'applications/nuance/worker/NuanceWorker.php',
|
||||
'OwnersConduitAPIMethod' => 'applications/owners/conduit/OwnersConduitAPIMethod.php',
|
||||
'OwnersEditConduitAPIMethod' => 'applications/owners/conduit/OwnersEditConduitAPIMethod.php',
|
||||
|
@ -3457,10 +3476,12 @@ phutil_register_library_map(array(
|
|||
'PhabricatorPeopleProfileManageController' => 'applications/people/controller/PhabricatorPeopleProfileManageController.php',
|
||||
'PhabricatorPeopleProfileMenuEngine' => 'applications/people/engine/PhabricatorPeopleProfileMenuEngine.php',
|
||||
'PhabricatorPeopleProfilePictureController' => 'applications/people/controller/PhabricatorPeopleProfilePictureController.php',
|
||||
'PhabricatorPeopleProfileRevisionsController' => 'applications/people/controller/PhabricatorPeopleProfileRevisionsController.php',
|
||||
'PhabricatorPeopleProfileTasksController' => 'applications/people/controller/PhabricatorPeopleProfileTasksController.php',
|
||||
'PhabricatorPeopleProfileViewController' => 'applications/people/controller/PhabricatorPeopleProfileViewController.php',
|
||||
'PhabricatorPeopleQuery' => 'applications/people/query/PhabricatorPeopleQuery.php',
|
||||
'PhabricatorPeopleRenameController' => 'applications/people/controller/PhabricatorPeopleRenameController.php',
|
||||
'PhabricatorPeopleRevisionsProfileMenuItem' => 'applications/people/menuitem/PhabricatorPeopleRevisionsProfileMenuItem.php',
|
||||
'PhabricatorPeopleSearchEngine' => 'applications/people/query/PhabricatorPeopleSearchEngine.php',
|
||||
'PhabricatorPeopleTasksProfileMenuItem' => 'applications/people/menuitem/PhabricatorPeopleTasksProfileMenuItem.php',
|
||||
'PhabricatorPeopleTestDataGenerator' => 'applications/people/lipsum/PhabricatorPeopleTestDataGenerator.php',
|
||||
|
@ -3615,6 +3636,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorProjectEditController' => 'applications/project/controller/PhabricatorProjectEditController.php',
|
||||
'PhabricatorProjectEditEngine' => 'applications/project/engine/PhabricatorProjectEditEngine.php',
|
||||
'PhabricatorProjectEditPictureController' => 'applications/project/controller/PhabricatorProjectEditPictureController.php',
|
||||
'PhabricatorProjectFilterTransaction' => 'applications/project/xaction/PhabricatorProjectFilterTransaction.php',
|
||||
'PhabricatorProjectFulltextEngine' => 'applications/project/search/PhabricatorProjectFulltextEngine.php',
|
||||
'PhabricatorProjectHeraldAction' => 'applications/project/herald/PhabricatorProjectHeraldAction.php',
|
||||
'PhabricatorProjectHeraldAdapter' => 'applications/project/herald/PhabricatorProjectHeraldAdapter.php',
|
||||
|
@ -3628,6 +3650,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorProjectListController' => 'applications/project/controller/PhabricatorProjectListController.php',
|
||||
'PhabricatorProjectListView' => 'applications/project/view/PhabricatorProjectListView.php',
|
||||
'PhabricatorProjectLockController' => 'applications/project/controller/PhabricatorProjectLockController.php',
|
||||
'PhabricatorProjectLockTransaction' => 'applications/project/xaction/PhabricatorProjectLockTransaction.php',
|
||||
'PhabricatorProjectLogicalAncestorDatasource' => 'applications/project/typeahead/PhabricatorProjectLogicalAncestorDatasource.php',
|
||||
'PhabricatorProjectLogicalDatasource' => 'applications/project/typeahead/PhabricatorProjectLogicalDatasource.php',
|
||||
'PhabricatorProjectLogicalOrNotDatasource' => 'applications/project/typeahead/PhabricatorProjectLogicalOrNotDatasource.php',
|
||||
|
@ -3645,6 +3668,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorProjectMembersRemoveController' => 'applications/project/controller/PhabricatorProjectMembersRemoveController.php',
|
||||
'PhabricatorProjectMembersViewController' => 'applications/project/controller/PhabricatorProjectMembersViewController.php',
|
||||
'PhabricatorProjectMenuItemController' => 'applications/project/controller/PhabricatorProjectMenuItemController.php',
|
||||
'PhabricatorProjectMilestoneTransaction' => 'applications/project/xaction/PhabricatorProjectMilestoneTransaction.php',
|
||||
'PhabricatorProjectMoveController' => 'applications/project/controller/PhabricatorProjectMoveController.php',
|
||||
'PhabricatorProjectNameContextFreeGrammar' => 'applications/project/lipsum/PhabricatorProjectNameContextFreeGrammar.php',
|
||||
'PhabricatorProjectNameTransaction' => 'applications/project/xaction/PhabricatorProjectNameTransaction.php',
|
||||
|
@ -3653,6 +3677,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorProjectOrUserDatasource' => 'applications/project/typeahead/PhabricatorProjectOrUserDatasource.php',
|
||||
'PhabricatorProjectOrUserFunctionDatasource' => 'applications/project/typeahead/PhabricatorProjectOrUserFunctionDatasource.php',
|
||||
'PhabricatorProjectPHIDResolver' => 'applications/phid/resolver/PhabricatorProjectPHIDResolver.php',
|
||||
'PhabricatorProjectParentTransaction' => 'applications/project/xaction/PhabricatorProjectParentTransaction.php',
|
||||
'PhabricatorProjectPictureProfileMenuItem' => 'applications/project/menuitem/PhabricatorProjectPictureProfileMenuItem.php',
|
||||
'PhabricatorProjectPointsProfileMenuItem' => 'applications/project/menuitem/PhabricatorProjectPointsProfileMenuItem.php',
|
||||
'PhabricatorProjectProfileController' => 'applications/project/controller/PhabricatorProjectProfileController.php',
|
||||
|
@ -3670,6 +3695,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorProjectSilencedEdgeType' => 'applications/project/edge/PhabricatorProjectSilencedEdgeType.php',
|
||||
'PhabricatorProjectSlug' => 'applications/project/storage/PhabricatorProjectSlug.php',
|
||||
'PhabricatorProjectSlugsTransaction' => 'applications/project/xaction/PhabricatorProjectSlugsTransaction.php',
|
||||
'PhabricatorProjectSortTransaction' => 'applications/project/xaction/PhabricatorProjectSortTransaction.php',
|
||||
'PhabricatorProjectStandardCustomField' => 'applications/project/customfield/PhabricatorProjectStandardCustomField.php',
|
||||
'PhabricatorProjectStatus' => 'applications/project/constants/PhabricatorProjectStatus.php',
|
||||
'PhabricatorProjectStatusTransaction' => 'applications/project/xaction/PhabricatorProjectStatusTransaction.php',
|
||||
|
@ -3681,6 +3707,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorProjectTransactionEditor' => 'applications/project/editor/PhabricatorProjectTransactionEditor.php',
|
||||
'PhabricatorProjectTransactionQuery' => 'applications/project/query/PhabricatorProjectTransactionQuery.php',
|
||||
'PhabricatorProjectTransactionType' => 'applications/project/xaction/PhabricatorProjectTransactionType.php',
|
||||
'PhabricatorProjectTypeTransaction' => 'applications/project/xaction/PhabricatorProjectTypeTransaction.php',
|
||||
'PhabricatorProjectUIEventListener' => 'applications/project/events/PhabricatorProjectUIEventListener.php',
|
||||
'PhabricatorProjectUpdateController' => 'applications/project/controller/PhabricatorProjectUpdateController.php',
|
||||
'PhabricatorProjectUserFunctionDatasource' => 'applications/project/typeahead/PhabricatorProjectUserFunctionDatasource.php',
|
||||
|
@ -3689,7 +3716,9 @@ phutil_register_library_map(array(
|
|||
'PhabricatorProjectWatchController' => 'applications/project/controller/PhabricatorProjectWatchController.php',
|
||||
'PhabricatorProjectWatcherListView' => 'applications/project/view/PhabricatorProjectWatcherListView.php',
|
||||
'PhabricatorProjectWorkboardBackgroundColor' => 'applications/project/constants/PhabricatorProjectWorkboardBackgroundColor.php',
|
||||
'PhabricatorProjectWorkboardBackgroundTransaction' => 'applications/project/xaction/PhabricatorProjectWorkboardBackgroundTransaction.php',
|
||||
'PhabricatorProjectWorkboardProfileMenuItem' => 'applications/project/menuitem/PhabricatorProjectWorkboardProfileMenuItem.php',
|
||||
'PhabricatorProjectWorkboardTransaction' => 'applications/project/xaction/PhabricatorProjectWorkboardTransaction.php',
|
||||
'PhabricatorProjectsAncestorsSearchEngineAttachment' => 'applications/project/engineextension/PhabricatorProjectsAncestorsSearchEngineAttachment.php',
|
||||
'PhabricatorProjectsCurtainExtension' => 'applications/project/engineextension/PhabricatorProjectsCurtainExtension.php',
|
||||
'PhabricatorProjectsEditEngineExtension' => 'applications/project/engineextension/PhabricatorProjectsEditEngineExtension.php',
|
||||
|
@ -4619,11 +4648,14 @@ phutil_register_library_map(array(
|
|||
'PhrictionDocument' => 'applications/phriction/storage/PhrictionDocument.php',
|
||||
'PhrictionDocumentAuthorHeraldField' => 'applications/phriction/herald/PhrictionDocumentAuthorHeraldField.php',
|
||||
'PhrictionDocumentContentHeraldField' => 'applications/phriction/herald/PhrictionDocumentContentHeraldField.php',
|
||||
'PhrictionDocumentContentTransaction' => 'applications/phriction/xaction/PhrictionDocumentContentTransaction.php',
|
||||
'PhrictionDocumentController' => 'applications/phriction/controller/PhrictionDocumentController.php',
|
||||
'PhrictionDocumentDeleteTransaction' => 'applications/phriction/xaction/PhrictionDocumentDeleteTransaction.php',
|
||||
'PhrictionDocumentFulltextEngine' => 'applications/phriction/search/PhrictionDocumentFulltextEngine.php',
|
||||
'PhrictionDocumentHeraldAdapter' => 'applications/phriction/herald/PhrictionDocumentHeraldAdapter.php',
|
||||
'PhrictionDocumentHeraldField' => 'applications/phriction/herald/PhrictionDocumentHeraldField.php',
|
||||
'PhrictionDocumentHeraldFieldGroup' => 'applications/phriction/herald/PhrictionDocumentHeraldFieldGroup.php',
|
||||
'PhrictionDocumentMoveAwayTransaction' => 'applications/phriction/xaction/PhrictionDocumentMoveAwayTransaction.php',
|
||||
'PhrictionDocumentMoveToTransaction' => 'applications/phriction/xaction/PhrictionDocumentMoveToTransaction.php',
|
||||
'PhrictionDocumentPHIDType' => 'applications/phriction/phid/PhrictionDocumentPHIDType.php',
|
||||
'PhrictionDocumentPathHeraldField' => 'applications/phriction/herald/PhrictionDocumentPathHeraldField.php',
|
||||
|
@ -5359,7 +5391,6 @@ phutil_register_library_map(array(
|
|||
'DifferentialDiffTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
||||
'DifferentialDiffViewController' => 'DifferentialController',
|
||||
'DifferentialDoorkeeperRevisionFeedStoryPublisher' => 'DoorkeeperFeedStoryPublisher',
|
||||
'DifferentialDraft' => 'DifferentialDAO',
|
||||
'DifferentialExactUserFunctionDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
|
||||
'DifferentialFieldParseException' => 'Exception',
|
||||
'DifferentialFieldValidationException' => 'Exception',
|
||||
|
@ -5602,6 +5633,7 @@ phutil_register_library_map(array(
|
|||
'DiffusionCommitHookEngine' => 'Phobject',
|
||||
'DiffusionCommitHookRejectException' => 'Exception',
|
||||
'DiffusionCommitListController' => 'DiffusionController',
|
||||
'DiffusionCommitListView' => 'AphrontView',
|
||||
'DiffusionCommitMergeHeraldField' => 'DiffusionCommitHeraldField',
|
||||
'DiffusionCommitMessageHeraldField' => 'DiffusionCommitHeraldField',
|
||||
'DiffusionCommitPackageAuditHeraldField' => 'DiffusionCommitHeraldField',
|
||||
|
@ -6562,6 +6594,7 @@ phutil_register_library_map(array(
|
|||
'ManiphestPointsConfigOptionType' => 'PhabricatorConfigJSONOptionType',
|
||||
'ManiphestPriorityConfigOptionType' => 'PhabricatorConfigJSONOptionType',
|
||||
'ManiphestPriorityEmailCommand' => 'ManiphestEmailCommand',
|
||||
'ManiphestPrioritySearchConduitAPIMethod' => 'ManiphestConduitAPIMethod',
|
||||
'ManiphestProjectNameFulltextEngineExtension' => 'PhabricatorFulltextEngineExtension',
|
||||
'ManiphestQueryConduitAPIMethod' => 'ManiphestConduitAPIMethod',
|
||||
'ManiphestQueryStatusesConduitAPIMethod' => 'ManiphestConduitAPIMethod',
|
||||
|
@ -6687,11 +6720,13 @@ phutil_register_library_map(array(
|
|||
'MultimeterLabel' => 'MultimeterDimension',
|
||||
'MultimeterSampleController' => 'MultimeterController',
|
||||
'MultimeterViewer' => 'MultimeterDimension',
|
||||
'NuanceCommandImplementation' => 'Phobject',
|
||||
'NuanceConduitAPIMethod' => 'ConduitAPIMethod',
|
||||
'NuanceConsoleController' => 'NuanceController',
|
||||
'NuanceContentSource' => 'PhabricatorContentSource',
|
||||
'NuanceController' => 'PhabricatorController',
|
||||
'NuanceDAO' => 'PhabricatorLiskDAO',
|
||||
'NuanceFormItemType' => 'NuanceItemType',
|
||||
'NuanceGitHubEventItemType' => 'NuanceItemType',
|
||||
'NuanceGitHubImportCursor' => 'NuanceImportCursor',
|
||||
'NuanceGitHubIssuesImportCursor' => 'NuanceGitHubImportCursor',
|
||||
|
@ -6717,16 +6752,25 @@ phutil_register_library_map(array(
|
|||
'PhabricatorPolicyInterface',
|
||||
),
|
||||
'NuanceItemCommandQuery' => 'NuanceQuery',
|
||||
'NuanceItemCommandSpec' => 'Phobject',
|
||||
'NuanceItemCommandTransaction' => 'NuanceItemTransactionType',
|
||||
'NuanceItemController' => 'NuanceController',
|
||||
'NuanceItemEditor' => 'PhabricatorApplicationTransactionEditor',
|
||||
'NuanceItemListController' => 'NuanceItemController',
|
||||
'NuanceItemManageController' => 'NuanceController',
|
||||
'NuanceItemOwnerTransaction' => 'NuanceItemTransactionType',
|
||||
'NuanceItemPHIDType' => 'PhabricatorPHIDType',
|
||||
'NuanceItemPropertyTransaction' => 'NuanceItemTransactionType',
|
||||
'NuanceItemQuery' => 'NuanceQuery',
|
||||
'NuanceItemQueueTransaction' => 'NuanceItemTransactionType',
|
||||
'NuanceItemRequestorTransaction' => 'NuanceItemTransactionType',
|
||||
'NuanceItemSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
||||
'NuanceItemSourceTransaction' => 'NuanceItemTransactionType',
|
||||
'NuanceItemStatusTransaction' => 'NuanceItemTransactionType',
|
||||
'NuanceItemTransaction' => 'NuanceTransaction',
|
||||
'NuanceItemTransactionComment' => 'PhabricatorApplicationTransactionComment',
|
||||
'NuanceItemTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
||||
'NuanceItemTransactionType' => 'PhabricatorModularTransactionType',
|
||||
'NuanceItemType' => 'Phobject',
|
||||
'NuanceItemUpdateWorker' => 'NuanceWorker',
|
||||
'NuanceItemViewController' => 'NuanceController',
|
||||
|
@ -6746,13 +6790,16 @@ phutil_register_library_map(array(
|
|||
'NuanceQueueEditEngine' => 'PhabricatorEditEngine',
|
||||
'NuanceQueueEditor' => 'PhabricatorApplicationTransactionEditor',
|
||||
'NuanceQueueListController' => 'NuanceQueueController',
|
||||
'NuanceQueueNameTransaction' => 'NuanceQueueTransactionType',
|
||||
'NuanceQueuePHIDType' => 'PhabricatorPHIDType',
|
||||
'NuanceQueueQuery' => 'NuanceQuery',
|
||||
'NuanceQueueSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
||||
'NuanceQueueTransaction' => 'NuanceTransaction',
|
||||
'NuanceQueueTransactionComment' => 'PhabricatorApplicationTransactionComment',
|
||||
'NuanceQueueTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
||||
'NuanceQueueTransactionType' => 'PhabricatorModularTransactionType',
|
||||
'NuanceQueueViewController' => 'NuanceQueueController',
|
||||
'NuanceQueueWorkController' => 'NuanceQueueController',
|
||||
'NuanceSchemaSpec' => 'PhabricatorConfigSchemaSpec',
|
||||
'NuanceSource' => array(
|
||||
'NuanceDAO',
|
||||
|
@ -6763,6 +6810,7 @@ phutil_register_library_map(array(
|
|||
'NuanceSourceActionController' => 'NuanceController',
|
||||
'NuanceSourceController' => 'NuanceController',
|
||||
'NuanceSourceDefaultEditCapability' => 'PhabricatorPolicyCapability',
|
||||
'NuanceSourceDefaultQueueTransaction' => 'NuanceSourceTransactionType',
|
||||
'NuanceSourceDefaultViewCapability' => 'PhabricatorPolicyCapability',
|
||||
'NuanceSourceDefinition' => 'Phobject',
|
||||
'NuanceSourceDefinitionTestCase' => 'PhabricatorTestCase',
|
||||
|
@ -6772,14 +6820,17 @@ phutil_register_library_map(array(
|
|||
'NuanceSourceListController' => 'NuanceSourceController',
|
||||
'NuanceSourceManageCapability' => 'PhabricatorPolicyCapability',
|
||||
'NuanceSourceNameNgrams' => 'PhabricatorSearchNgrams',
|
||||
'NuanceSourceNameTransaction' => 'NuanceSourceTransactionType',
|
||||
'NuanceSourcePHIDType' => 'PhabricatorPHIDType',
|
||||
'NuanceSourceQuery' => 'NuanceQuery',
|
||||
'NuanceSourceSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
||||
'NuanceSourceTransaction' => 'NuanceTransaction',
|
||||
'NuanceSourceTransactionComment' => 'PhabricatorApplicationTransactionComment',
|
||||
'NuanceSourceTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
||||
'NuanceSourceTransactionType' => 'PhabricatorModularTransactionType',
|
||||
'NuanceSourceViewController' => 'NuanceSourceController',
|
||||
'NuanceTransaction' => 'PhabricatorApplicationTransaction',
|
||||
'NuanceTransaction' => 'PhabricatorModularTransaction',
|
||||
'NuanceTrashCommand' => 'NuanceCommandImplementation',
|
||||
'NuanceWorker' => 'PhabricatorWorker',
|
||||
'OwnersConduitAPIMethod' => 'ConduitAPIMethod',
|
||||
'OwnersEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod',
|
||||
|
@ -8825,10 +8876,12 @@ phutil_register_library_map(array(
|
|||
'PhabricatorPeopleProfileManageController' => 'PhabricatorPeopleProfileController',
|
||||
'PhabricatorPeopleProfileMenuEngine' => 'PhabricatorProfileMenuEngine',
|
||||
'PhabricatorPeopleProfilePictureController' => 'PhabricatorPeopleProfileController',
|
||||
'PhabricatorPeopleProfileRevisionsController' => 'PhabricatorPeopleProfileController',
|
||||
'PhabricatorPeopleProfileTasksController' => 'PhabricatorPeopleProfileController',
|
||||
'PhabricatorPeopleProfileViewController' => 'PhabricatorPeopleProfileController',
|
||||
'PhabricatorPeopleQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||
'PhabricatorPeopleRenameController' => 'PhabricatorPeopleController',
|
||||
'PhabricatorPeopleRevisionsProfileMenuItem' => 'PhabricatorProfileMenuItem',
|
||||
'PhabricatorPeopleSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
||||
'PhabricatorPeopleTasksProfileMenuItem' => 'PhabricatorProfileMenuItem',
|
||||
'PhabricatorPeopleTestDataGenerator' => 'PhabricatorTestDataGenerator',
|
||||
|
@ -9032,6 +9085,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorProjectEditController' => 'PhabricatorProjectController',
|
||||
'PhabricatorProjectEditEngine' => 'PhabricatorEditEngine',
|
||||
'PhabricatorProjectEditPictureController' => 'PhabricatorProjectController',
|
||||
'PhabricatorProjectFilterTransaction' => 'PhabricatorProjectTransactionType',
|
||||
'PhabricatorProjectFulltextEngine' => 'PhabricatorFulltextEngine',
|
||||
'PhabricatorProjectHeraldAction' => 'HeraldAction',
|
||||
'PhabricatorProjectHeraldAdapter' => 'HeraldAdapter',
|
||||
|
@ -9044,6 +9098,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorProjectListController' => 'PhabricatorProjectController',
|
||||
'PhabricatorProjectListView' => 'AphrontView',
|
||||
'PhabricatorProjectLockController' => 'PhabricatorProjectController',
|
||||
'PhabricatorProjectLockTransaction' => 'PhabricatorProjectTransactionType',
|
||||
'PhabricatorProjectLogicalAncestorDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
|
||||
'PhabricatorProjectLogicalDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
|
||||
'PhabricatorProjectLogicalOrNotDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
|
||||
|
@ -9061,6 +9116,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorProjectMembersRemoveController' => 'PhabricatorProjectController',
|
||||
'PhabricatorProjectMembersViewController' => 'PhabricatorProjectController',
|
||||
'PhabricatorProjectMenuItemController' => 'PhabricatorProjectController',
|
||||
'PhabricatorProjectMilestoneTransaction' => 'PhabricatorProjectTypeTransaction',
|
||||
'PhabricatorProjectMoveController' => 'PhabricatorProjectController',
|
||||
'PhabricatorProjectNameContextFreeGrammar' => 'PhutilContextFreeGrammar',
|
||||
'PhabricatorProjectNameTransaction' => 'PhabricatorProjectTransactionType',
|
||||
|
@ -9069,6 +9125,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorProjectOrUserDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
|
||||
'PhabricatorProjectOrUserFunctionDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
|
||||
'PhabricatorProjectPHIDResolver' => 'PhabricatorPHIDResolver',
|
||||
'PhabricatorProjectParentTransaction' => 'PhabricatorProjectTypeTransaction',
|
||||
'PhabricatorProjectPictureProfileMenuItem' => 'PhabricatorProfileMenuItem',
|
||||
'PhabricatorProjectPointsProfileMenuItem' => 'PhabricatorProfileMenuItem',
|
||||
'PhabricatorProjectProfileController' => 'PhabricatorProjectController',
|
||||
|
@ -9086,6 +9143,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorProjectSilencedEdgeType' => 'PhabricatorEdgeType',
|
||||
'PhabricatorProjectSlug' => 'PhabricatorProjectDAO',
|
||||
'PhabricatorProjectSlugsTransaction' => 'PhabricatorProjectTransactionType',
|
||||
'PhabricatorProjectSortTransaction' => 'PhabricatorProjectTransactionType',
|
||||
'PhabricatorProjectStandardCustomField' => array(
|
||||
'PhabricatorProjectCustomField',
|
||||
'PhabricatorStandardCustomFieldInterface',
|
||||
|
@ -9100,6 +9158,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorProjectTransactionEditor' => 'PhabricatorApplicationTransactionEditor',
|
||||
'PhabricatorProjectTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
||||
'PhabricatorProjectTransactionType' => 'PhabricatorModularTransactionType',
|
||||
'PhabricatorProjectTypeTransaction' => 'PhabricatorProjectTransactionType',
|
||||
'PhabricatorProjectUIEventListener' => 'PhabricatorEventListener',
|
||||
'PhabricatorProjectUpdateController' => 'PhabricatorProjectController',
|
||||
'PhabricatorProjectUserFunctionDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
|
||||
|
@ -9108,7 +9167,9 @@ phutil_register_library_map(array(
|
|||
'PhabricatorProjectWatchController' => 'PhabricatorProjectController',
|
||||
'PhabricatorProjectWatcherListView' => 'PhabricatorProjectUserListView',
|
||||
'PhabricatorProjectWorkboardBackgroundColor' => 'Phobject',
|
||||
'PhabricatorProjectWorkboardBackgroundTransaction' => 'PhabricatorProjectTransactionType',
|
||||
'PhabricatorProjectWorkboardProfileMenuItem' => 'PhabricatorProfileMenuItem',
|
||||
'PhabricatorProjectWorkboardTransaction' => 'PhabricatorProjectTransactionType',
|
||||
'PhabricatorProjectsAncestorsSearchEngineAttachment' => 'PhabricatorSearchEngineAttachment',
|
||||
'PhabricatorProjectsCurtainExtension' => 'PHUICurtainExtension',
|
||||
'PhabricatorProjectsEditEngineExtension' => 'PhabricatorEditEngineExtension',
|
||||
|
@ -10266,11 +10327,14 @@ phutil_register_library_map(array(
|
|||
),
|
||||
'PhrictionDocumentAuthorHeraldField' => 'PhrictionDocumentHeraldField',
|
||||
'PhrictionDocumentContentHeraldField' => 'PhrictionDocumentHeraldField',
|
||||
'PhrictionDocumentContentTransaction' => 'PhrictionDocumentTransactionType',
|
||||
'PhrictionDocumentController' => 'PhrictionController',
|
||||
'PhrictionDocumentDeleteTransaction' => 'PhrictionDocumentTransactionType',
|
||||
'PhrictionDocumentFulltextEngine' => 'PhabricatorFulltextEngine',
|
||||
'PhrictionDocumentHeraldAdapter' => 'HeraldAdapter',
|
||||
'PhrictionDocumentHeraldField' => 'HeraldField',
|
||||
'PhrictionDocumentHeraldFieldGroup' => 'HeraldFieldGroup',
|
||||
'PhrictionDocumentMoveAwayTransaction' => 'PhrictionDocumentTransactionType',
|
||||
'PhrictionDocumentMoveToTransaction' => 'PhrictionDocumentTransactionType',
|
||||
'PhrictionDocumentPHIDType' => 'PhabricatorPHIDType',
|
||||
'PhrictionDocumentPathHeraldField' => 'PhrictionDocumentHeraldField',
|
||||
|
|
|
@ -125,7 +125,7 @@ final class PhabricatorCalendarEventViewController
|
|||
->setName(pht('Imported'))
|
||||
->setIcon('fa-download')
|
||||
->setHref($event->getImportSource()->getURI())
|
||||
->setShade('orange'));
|
||||
->setColor(PHUITagView::COLOR_ORANGE));
|
||||
}
|
||||
|
||||
foreach ($this->buildRSVPActions($event) as $action) {
|
||||
|
|
|
@ -29,7 +29,7 @@ final class PHUIUserAvailabilityView
|
|||
|
||||
$away_tag = id(new PHUITagView())
|
||||
->setType(PHUITagView::TYPE_SHADE)
|
||||
->setShade($color)
|
||||
->setColor($color)
|
||||
->setName($name)
|
||||
->setDotColor($color);
|
||||
|
||||
|
|
|
@ -71,7 +71,7 @@ abstract class ConpherenceController extends PhabricatorController {
|
|||
if (strlen($data['topic'])) {
|
||||
$topic = id(new PHUITagView())
|
||||
->setName($data['topic'])
|
||||
->setShade(PHUITagView::COLOR_VIOLET)
|
||||
->setColor(PHUITagView::COLOR_VIOLET)
|
||||
->setType(PHUITagView::TYPE_SHADE)
|
||||
->addClass('conpherence-header-topic');
|
||||
$header->addTag($topic);
|
||||
|
|
|
@ -19,10 +19,9 @@ final class PhabricatorDaemonLogGarbageCollector
|
|||
|
||||
queryfx(
|
||||
$conn_w,
|
||||
'DELETE FROM %T WHERE dateCreated < %d AND status != %s LIMIT 100',
|
||||
'DELETE FROM %T WHERE dateModified < %d LIMIT 100',
|
||||
$table->getTableName(),
|
||||
$this->getGarbageEpoch(),
|
||||
PhabricatorDaemonLog::STATUS_RUNNING);
|
||||
$this->getGarbageEpoch());
|
||||
|
||||
return ($conn_w->getAffectedRows() == 100);
|
||||
}
|
||||
|
|
|
@ -37,13 +37,13 @@ final class PhabricatorDaemonLog extends PhabricatorDaemonDAO
|
|||
'status' => array(
|
||||
'columns' => array('status'),
|
||||
),
|
||||
'dateCreated' => array(
|
||||
'columns' => array('dateCreated'),
|
||||
),
|
||||
'key_daemonID' => array(
|
||||
'columns' => array('daemonID'),
|
||||
'unique' => true,
|
||||
),
|
||||
'key_modified' => array(
|
||||
'columns' => array('dateModified'),
|
||||
),
|
||||
),
|
||||
) + parent::getConfiguration();
|
||||
}
|
||||
|
|
|
@ -47,6 +47,7 @@ final class PhabricatorDashboardViewController
|
|||
->setTag('a')
|
||||
->setText('Install Dashboard')
|
||||
->setIcon('fa-plus')
|
||||
->setColor(PHUIButtonView::GREEN)
|
||||
->setWorkflow(true)
|
||||
->setHref($this->getApplicationURI("/install/{$id}/"));
|
||||
$header->addActionLink($install_button);
|
||||
|
|
|
@ -65,7 +65,7 @@ final class DifferentialRevisionStatus extends Phobject {
|
|||
$tag = id(new PHUITagView())
|
||||
->setName($status_name)
|
||||
->setIcon(self::getRevisionStatusIcon($status))
|
||||
->setShade(self::getRevisionStatusColor($status))
|
||||
->setColor(self::getRevisionStatusColor($status))
|
||||
->setType(PHUITagView::TYPE_SHADE);
|
||||
|
||||
return $tag;
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class DifferentialDraft extends DifferentialDAO {
|
||||
|
||||
protected $objectPHID;
|
||||
protected $authorPHID;
|
||||
protected $draftKey;
|
||||
|
||||
protected function getConfiguration() {
|
||||
return array(
|
||||
self::CONFIG_COLUMN_SCHEMA => array(
|
||||
'draftKey' => 'text64',
|
||||
),
|
||||
self::CONFIG_KEY_SCHEMA => array(
|
||||
'key_unique' => array(
|
||||
'columns' => array('objectPHID', 'authorPHID', 'draftKey'),
|
||||
'unique' => true,
|
||||
),
|
||||
),
|
||||
) + parent::getConfiguration();
|
||||
}
|
||||
|
||||
}
|
|
@ -50,7 +50,8 @@ final class DifferentialRevisionAcceptTransaction
|
|||
|
||||
protected function getActionOptions(
|
||||
PhabricatorUser $viewer,
|
||||
DifferentialRevision $revision) {
|
||||
DifferentialRevision $revision,
|
||||
$include_accepted = false) {
|
||||
|
||||
$reviewers = $revision->getReviewers();
|
||||
|
||||
|
@ -98,10 +99,13 @@ final class DifferentialRevisionAcceptTransaction
|
|||
}
|
||||
}
|
||||
|
||||
if ($reviewer->isAccepted($diff_phid)) {
|
||||
// If a reviewer is already in a full "accepted" state, don't
|
||||
// include that reviewer as an option.
|
||||
continue;
|
||||
if (!$include_accepted) {
|
||||
if ($reviewer->isAccepted($diff_phid)) {
|
||||
// If a reviewer is already in a full "accepted" state, don't
|
||||
// include that reviewer as an option unless we're listing all
|
||||
// reviwers, including reviewers who have already accepted.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$reviewer_phids[$reviewer_phid] = $reviewer_phid;
|
||||
|
@ -185,7 +189,12 @@ final class DifferentialRevisionAcceptTransaction
|
|||
'least one reviewer.'));
|
||||
}
|
||||
|
||||
list($options) = $this->getActionOptions($actor, $object);
|
||||
// NOTE: We're including reviewers who have already been accepted in this
|
||||
// check. Legitimate users may race one another to accept on behalf of
|
||||
// packages. If we get a form submission which includes a reviewer which
|
||||
// someone has already accepted, that's fine. See T12757.
|
||||
|
||||
list($options) = $this->getActionOptions($actor, $object, true);
|
||||
foreach ($value as $phid) {
|
||||
if (!isset($options[$phid])) {
|
||||
throw new Exception(
|
||||
|
|
|
@ -17,6 +17,16 @@ abstract class DifferentialRevisionReviewTransaction
|
|||
$viewer = $this->getActor();
|
||||
list($options, $default) = $this->getActionOptions($viewer, $object);
|
||||
|
||||
// Remove reviewers which aren't actionable. In the case of "Accept", we
|
||||
// may allow the transaction to proceed with some reviewers who have
|
||||
// already accepted, to avoid race conditions where two reviewers fill
|
||||
// out the form at the same time and accept on behalf of the same package.
|
||||
// It's okay for these reviewers to survive validation, but they should
|
||||
// not survive beyond this point.
|
||||
$value = array_fuse($value);
|
||||
$value = array_intersect($value, array_keys($options));
|
||||
$value = array_values($value);
|
||||
|
||||
sort($default);
|
||||
sort($value);
|
||||
|
||||
|
|
|
@ -332,7 +332,7 @@ abstract class DiffusionController extends PhabricatorController {
|
|||
|
||||
$tag = id(new PHUITagView())
|
||||
->setName($commit)
|
||||
->setShade('indigo')
|
||||
->setColor(PHUITagView::COLOR_INDIGO)
|
||||
->setType(PHUITagView::TYPE_SHADE);
|
||||
|
||||
return $tag;
|
||||
|
|
|
@ -83,11 +83,11 @@ final class DiffusionRepositoryManagePanelsController
|
|||
->setTag('a')
|
||||
->setText(pht('View Repository'))
|
||||
->setHref($repository->getURI())
|
||||
->setIcon('fa-code'));
|
||||
->setIcon('fa-code')
|
||||
->setColor(PHUIButtonView::GREEN));
|
||||
|
||||
$view = id(new PHUITwoColumnView())
|
||||
->setHeader($header)
|
||||
->setNavigation($nav)
|
||||
->setMainColumn($content);
|
||||
|
||||
$curtain = $panel->buildManagementPanelCurtain();
|
||||
|
@ -98,6 +98,7 @@ final class DiffusionRepositoryManagePanelsController
|
|||
return $this->newPage()
|
||||
->setTitle($title)
|
||||
->setCrumbs($crumbs)
|
||||
->setNavigation($nav)
|
||||
->appendChild($view);
|
||||
}
|
||||
|
||||
|
@ -112,6 +113,12 @@ final class DiffusionRepositoryManagePanelsController
|
|||
$nav = id(new AphrontSideNavFilterView())
|
||||
->setBaseURI($base_uri);
|
||||
|
||||
$item = id(new PHUIListItemView())
|
||||
->setName(pht('manage'))
|
||||
->setType(PHUIListItemView::TYPE_LABEL);
|
||||
|
||||
$nav->addMenuItem($item);
|
||||
|
||||
foreach ($panels as $panel) {
|
||||
$key = $panel->getManagementPanelKey();
|
||||
$label = $panel->getManagementPanelLabel();
|
||||
|
|
|
@ -37,9 +37,10 @@ final class DiffusionRepositoryActionsManagementPanel
|
|||
);
|
||||
}
|
||||
|
||||
protected function buildManagementPanelActions() {
|
||||
public function buildManagementPanelCurtain() {
|
||||
$repository = $this->getRepository();
|
||||
$viewer = $this->getViewer();
|
||||
$action_list = $this->getNewActionList();
|
||||
|
||||
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
||||
$viewer,
|
||||
|
@ -48,14 +49,15 @@ final class DiffusionRepositoryActionsManagementPanel
|
|||
|
||||
$actions_uri = $this->getEditPageURI();
|
||||
|
||||
return array(
|
||||
$action_list->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setIcon('fa-pencil')
|
||||
->setName(pht('Edit Actions'))
|
||||
->setHref($actions_uri)
|
||||
->setDisabled(!$can_edit)
|
||||
->setWorkflow(!$can_edit),
|
||||
);
|
||||
->setWorkflow(!$can_edit));
|
||||
|
||||
return $this->getNewCurtainView($action_list);
|
||||
}
|
||||
|
||||
public function buildManagementPanelContent() {
|
||||
|
@ -63,8 +65,7 @@ final class DiffusionRepositoryActionsManagementPanel
|
|||
$viewer = $this->getViewer();
|
||||
|
||||
$view = id(new PHUIPropertyListView())
|
||||
->setViewer($viewer)
|
||||
->setActionList($this->newActions());
|
||||
->setViewer($viewer);
|
||||
|
||||
$notify = $repository->getDetail('herald-disabled')
|
||||
? pht('Off')
|
||||
|
|
|
@ -46,9 +46,10 @@ final class DiffusionRepositoryAutomationManagementPanel
|
|||
return 'fa-truck';
|
||||
}
|
||||
|
||||
protected function buildManagementPanelActions() {
|
||||
public function buildManagementPanelCurtain() {
|
||||
$repository = $this->getRepository();
|
||||
$viewer = $this->getViewer();
|
||||
$action_list = $this->getNewActionList();
|
||||
|
||||
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
||||
$viewer,
|
||||
|
@ -60,20 +61,23 @@ final class DiffusionRepositoryAutomationManagementPanel
|
|||
$automation_uri = $this->getEditPageURI();
|
||||
$test_uri = $repository->getPathURI('edit/testautomation/');
|
||||
|
||||
return array(
|
||||
$action_list->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setIcon('fa-pencil')
|
||||
->setName(pht('Edit Automation'))
|
||||
->setHref($automation_uri)
|
||||
->setDisabled(!$can_edit)
|
||||
->setWorkflow(!$can_edit),
|
||||
->setWorkflow(!$can_edit));
|
||||
|
||||
$action_list->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setIcon('fa-gamepad')
|
||||
->setName(pht('Test Configuration'))
|
||||
->setWorkflow(true)
|
||||
->setDisabled(!$can_test)
|
||||
->setHref($test_uri),
|
||||
);
|
||||
->setHref($test_uri));
|
||||
|
||||
return $this->getNewCurtainView($action_list);
|
||||
}
|
||||
|
||||
public function buildManagementPanelContent() {
|
||||
|
@ -81,8 +85,7 @@ final class DiffusionRepositoryAutomationManagementPanel
|
|||
$viewer = $this->getViewer();
|
||||
|
||||
$view = id(new PHUIPropertyListView())
|
||||
->setViewer($viewer)
|
||||
->setActionList($this->newActions());
|
||||
->setViewer($viewer);
|
||||
|
||||
$blueprint_phids = $repository->getAutomationBlueprintPHIDs();
|
||||
if (!$blueprint_phids) {
|
||||
|
|
|
@ -33,9 +33,10 @@ final class DiffusionRepositoryBasicsManagementPanel
|
|||
);
|
||||
}
|
||||
|
||||
protected function buildManagementPanelActions() {
|
||||
public function buildManagementPanelCurtain() {
|
||||
$repository = $this->getRepository();
|
||||
$viewer = $this->getViewer();
|
||||
$action_list = $this->getNewActionList();
|
||||
|
||||
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
||||
$viewer,
|
||||
|
@ -67,38 +68,47 @@ final class DiffusionRepositoryBasicsManagementPanel
|
|||
$can_dangerous = ($can_edit && $repository->canAllowDangerousChanges());
|
||||
}
|
||||
|
||||
return array(
|
||||
$action_list->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setIcon('fa-pencil')
|
||||
->setName(pht('Edit Basic Information'))
|
||||
->setHref($edit_uri)
|
||||
->setDisabled(!$can_edit)
|
||||
->setWorkflow(!$can_edit),
|
||||
->setWorkflow(!$can_edit));
|
||||
|
||||
$action_list->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setIcon('fa-text-width')
|
||||
->setName(pht('Edit Text Encoding'))
|
||||
->setHref($encoding_uri)
|
||||
->setDisabled(!$can_edit)
|
||||
->setWorkflow(!$can_edit),
|
||||
->setWorkflow(!$can_edit));
|
||||
|
||||
$action_list->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setIcon($dangerous_icon)
|
||||
->setName($dangerous_name)
|
||||
->setHref($dangerous_uri)
|
||||
->setDisabled(!$can_dangerous)
|
||||
->setWorkflow(true),
|
||||
->setWorkflow(true));
|
||||
|
||||
$action_list->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setHref($activate_uri)
|
||||
->setIcon($activate_icon)
|
||||
->setName($activate_label)
|
||||
->setDisabled(!$can_edit)
|
||||
->setWorkflow(true),
|
||||
->setWorkflow(true));
|
||||
|
||||
$action_list->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setName(pht('Delete Repository'))
|
||||
->setIcon('fa-times')
|
||||
->setHref($delete_uri)
|
||||
->setDisabled(true)
|
||||
->setWorkflow(true),
|
||||
);
|
||||
->setWorkflow(true));
|
||||
|
||||
return $this->getNewCurtainView($action_list);
|
||||
}
|
||||
|
||||
public function buildManagementPanelContent() {
|
||||
|
@ -108,6 +118,7 @@ final class DiffusionRepositoryBasicsManagementPanel
|
|||
|
||||
$repository = $this->getRepository();
|
||||
$is_new = $repository->isNewlyInitialized();
|
||||
$info_view = null;
|
||||
if ($is_new) {
|
||||
$messages = array();
|
||||
|
||||
|
@ -131,8 +142,6 @@ final class DiffusionRepositoryBasicsManagementPanel
|
|||
$info_view = id(new PHUIInfoView())
|
||||
->setSeverity(PHUIInfoView::SEVERITY_NOTICE)
|
||||
->setErrors($messages);
|
||||
|
||||
$basics->setInfoView($info_view);
|
||||
}
|
||||
|
||||
$result[] = $basics;
|
||||
|
@ -142,7 +151,7 @@ final class DiffusionRepositoryBasicsManagementPanel
|
|||
$result[] = $this->newBox(pht('Description'), $description);
|
||||
}
|
||||
|
||||
return $result;
|
||||
return array($info_view, $result);
|
||||
}
|
||||
|
||||
private function buildBasics() {
|
||||
|
@ -150,8 +159,7 @@ final class DiffusionRepositoryBasicsManagementPanel
|
|||
$viewer = $this->getViewer();
|
||||
|
||||
$view = id(new PHUIPropertyListView())
|
||||
->setViewer($viewer)
|
||||
->setActionList($this->newActions());
|
||||
->setViewer($viewer);
|
||||
|
||||
$name = $repository->getName();
|
||||
$view->addProperty(pht('Name'), $name);
|
||||
|
|
|
@ -41,9 +41,10 @@ final class DiffusionRepositoryBranchesManagementPanel
|
|||
);
|
||||
}
|
||||
|
||||
protected function buildManagementPanelActions() {
|
||||
public function buildManagementPanelCurtain() {
|
||||
$repository = $this->getRepository();
|
||||
$viewer = $this->getViewer();
|
||||
$action_list = $this->getNewActionList();
|
||||
|
||||
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
||||
$viewer,
|
||||
|
@ -52,14 +53,15 @@ final class DiffusionRepositoryBranchesManagementPanel
|
|||
|
||||
$branches_uri = $this->getEditPageURI();
|
||||
|
||||
return array(
|
||||
$action_list->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setIcon('fa-pencil')
|
||||
->setName(pht('Edit Branches'))
|
||||
->setHref($branches_uri)
|
||||
->setDisabled(!$can_edit)
|
||||
->setWorkflow(!$can_edit),
|
||||
);
|
||||
->setWorkflow(!$can_edit));
|
||||
|
||||
return $this->getNewCurtainView($action_list);
|
||||
}
|
||||
|
||||
public function buildManagementPanelContent() {
|
||||
|
@ -67,8 +69,7 @@ final class DiffusionRepositoryBranchesManagementPanel
|
|||
$viewer = $this->getViewer();
|
||||
|
||||
$view = id(new PHUIPropertyListView())
|
||||
->setViewer($viewer)
|
||||
->setActionList($this->newActions());
|
||||
->setViewer($viewer);
|
||||
|
||||
$default_branch = nonempty(
|
||||
$repository->getHumanReadableDetail('default-branch'),
|
||||
|
|
|
@ -21,6 +21,10 @@ final class DiffusionRepositoryDocumentationManagementPanel
|
|||
return null;
|
||||
}
|
||||
|
||||
public function buildManagementPanelCurtain() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getPanelNavigationURI() {
|
||||
return PhabricatorEnv::getDoclink(
|
||||
'Diffusion User Guide: Managing Repositories');
|
||||
|
|
|
@ -21,5 +21,8 @@ final class DiffusionRepositoryHistoryManagementPanel
|
|||
return $this->newTimeline();
|
||||
}
|
||||
|
||||
public function buildManagementPanelCurtain() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@ abstract class DiffusionRepositoryManagementPanel
|
|||
abstract public function getManagementPanelLabel();
|
||||
abstract public function getManagementPanelOrder();
|
||||
abstract public function buildManagementPanelContent();
|
||||
abstract public function buildManagementPanelCurtain();
|
||||
|
||||
public function getManagementPanelIcon() {
|
||||
return 'fa-pencil';
|
||||
|
@ -51,41 +52,20 @@ abstract class DiffusionRepositoryManagementPanel
|
|||
return true;
|
||||
}
|
||||
|
||||
final protected function newActions() {
|
||||
$actions = $this->buildManagementPanelActions();
|
||||
if (!$actions) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getNewActionList() {
|
||||
$viewer = $this->getViewer();
|
||||
$action_id = celerity_generate_unique_node_id();
|
||||
|
||||
$action_list = id(new PhabricatorActionListView())
|
||||
->setViewer($viewer);
|
||||
|
||||
foreach ($actions as $action) {
|
||||
$action_list->addAction($action);
|
||||
}
|
||||
|
||||
return $action_list;
|
||||
return id(new PhabricatorActionListView())
|
||||
->setViewer($viewer)
|
||||
->setID($action_id);
|
||||
}
|
||||
|
||||
public function buildManagementPanelCurtain() {
|
||||
// TODO: Delete or fix this, curtains always render in the left gutter
|
||||
// at the moment.
|
||||
return null;
|
||||
|
||||
$actions = $this->newActions();
|
||||
if (!$actions) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getNewCurtainView(PhabricatorActionListView $action_list) {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$curtain = id(new PHUICurtainView())
|
||||
return id(new PHUICurtainView())
|
||||
->setViewer($viewer)
|
||||
->setActionList($actions);
|
||||
|
||||
return $curtain;
|
||||
->setActionList($action_list);
|
||||
}
|
||||
|
||||
public static function getAllPanels() {
|
||||
|
|
|
@ -54,9 +54,10 @@ final class DiffusionRepositoryPoliciesManagementPanel
|
|||
);
|
||||
}
|
||||
|
||||
protected function buildManagementPanelActions() {
|
||||
public function buildManagementPanelCurtain() {
|
||||
$repository = $this->getRepository();
|
||||
$viewer = $this->getViewer();
|
||||
$action_list = $this->getNewActionList();
|
||||
|
||||
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
||||
$viewer,
|
||||
|
@ -65,14 +66,15 @@ final class DiffusionRepositoryPoliciesManagementPanel
|
|||
|
||||
$edit_uri = $this->getEditPageURI();
|
||||
|
||||
return array(
|
||||
$action_list->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setIcon('fa-pencil')
|
||||
->setName(pht('Edit Policies'))
|
||||
->setHref($edit_uri)
|
||||
->setDisabled(!$can_edit)
|
||||
->setWorkflow(!$can_edit),
|
||||
);
|
||||
->setWorkflow(!$can_edit));
|
||||
|
||||
return $this->getNewCurtainView($action_list);
|
||||
}
|
||||
|
||||
public function buildManagementPanelContent() {
|
||||
|
@ -80,8 +82,7 @@ final class DiffusionRepositoryPoliciesManagementPanel
|
|||
$viewer = $this->getViewer();
|
||||
|
||||
$view = id(new PHUIPropertyListView())
|
||||
->setViewer($viewer)
|
||||
->setActionList($this->newActions());
|
||||
->setViewer($viewer);
|
||||
|
||||
$descriptions = PhabricatorPolicyQuery::renderPolicyDescriptions(
|
||||
$viewer,
|
||||
|
|
|
@ -37,9 +37,10 @@ final class DiffusionRepositoryStagingManagementPanel
|
|||
);
|
||||
}
|
||||
|
||||
protected function buildManagementPanelActions() {
|
||||
public function buildManagementPanelCurtain() {
|
||||
$repository = $this->getRepository();
|
||||
$viewer = $this->getViewer();
|
||||
$action_list = $this->getNewActionList();
|
||||
|
||||
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
||||
$viewer,
|
||||
|
@ -48,14 +49,15 @@ final class DiffusionRepositoryStagingManagementPanel
|
|||
|
||||
$staging_uri = $this->getEditPageURI();
|
||||
|
||||
return array(
|
||||
$action_list->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setIcon('fa-pencil')
|
||||
->setName(pht('Edit Staging'))
|
||||
->setHref($staging_uri)
|
||||
->setDisabled(!$can_edit)
|
||||
->setWorkflow(!$can_edit),
|
||||
);
|
||||
->setWorkflow(!$can_edit));
|
||||
|
||||
return $this->getNewCurtainView($action_list);
|
||||
}
|
||||
|
||||
public function buildManagementPanelContent() {
|
||||
|
@ -63,8 +65,7 @@ final class DiffusionRepositoryStagingManagementPanel
|
|||
$viewer = $this->getViewer();
|
||||
|
||||
$view = id(new PHUIPropertyListView())
|
||||
->setViewer($viewer)
|
||||
->setActionList($this->newActions());
|
||||
->setViewer($viewer);
|
||||
|
||||
$staging_uri = $repository->getStagingURI();
|
||||
if (!$staging_uri) {
|
||||
|
|
|
@ -28,9 +28,10 @@ final class DiffusionRepositoryStatusManagementPanel
|
|||
return 'fa-check grey';
|
||||
}
|
||||
|
||||
protected function buildManagementPanelActions() {
|
||||
public function buildManagementPanelCurtain() {
|
||||
$repository = $this->getRepository();
|
||||
$viewer = $this->getViewer();
|
||||
$action_list = $this->getNewActionList();
|
||||
|
||||
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
||||
$viewer,
|
||||
|
@ -39,14 +40,15 @@ final class DiffusionRepositoryStatusManagementPanel
|
|||
|
||||
$update_uri = $repository->getPathURI('edit/update/');
|
||||
|
||||
return array(
|
||||
$action_list->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setIcon('fa-refresh')
|
||||
->setName(pht('Update Now'))
|
||||
->setWorkflow(true)
|
||||
->setDisabled(!$can_edit)
|
||||
->setHref($update_uri),
|
||||
);
|
||||
->setHref($update_uri));
|
||||
|
||||
return $this->getNewCurtainView($action_list);
|
||||
}
|
||||
|
||||
public function buildManagementPanelContent() {
|
||||
|
@ -54,8 +56,7 @@ final class DiffusionRepositoryStatusManagementPanel
|
|||
$viewer = $this->getViewer();
|
||||
|
||||
$view = id(new PHUIPropertyListView())
|
||||
->setViewer($viewer)
|
||||
->setActionList($this->newActions());
|
||||
->setViewer($viewer);
|
||||
|
||||
$view->addProperty(
|
||||
pht('Update Frequency'),
|
||||
|
|
|
@ -25,6 +25,22 @@ final class DiffusionRepositoryStorageManagementPanel
|
|||
}
|
||||
}
|
||||
|
||||
public function buildManagementPanelCurtain() {
|
||||
$repository = $this->getRepository();
|
||||
$viewer = $this->getViewer();
|
||||
$action_list = $this->getNewActionList();
|
||||
|
||||
$doc_href = PhabricatorEnv::getDoclink('Cluster: Repositories');
|
||||
|
||||
$action_list->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setIcon('fa-book')
|
||||
->setHref($doc_href)
|
||||
->setName(pht('Cluster Documentation')));
|
||||
|
||||
return $this->getNewCurtainView($action_list);
|
||||
}
|
||||
|
||||
public function buildManagementPanelContent() {
|
||||
return array(
|
||||
$this->buildStorageStatusPanel(),
|
||||
|
@ -55,13 +71,9 @@ final class DiffusionRepositoryStorageManagementPanel
|
|||
$view->addProperty(pht('Storage Path'), $storage_path);
|
||||
$view->addProperty(pht('Storage Cluster'), $storage_service);
|
||||
|
||||
$header = id(new PHUIHeaderView())
|
||||
->setHeader(pht('Storage'));
|
||||
|
||||
return id(new PHUIObjectBoxView())
|
||||
->setHeader($header)
|
||||
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
||||
->addPropertyList($view);
|
||||
$box = $this->newBox(pht('Storage'), null);
|
||||
$box->addPropertyList($view);
|
||||
return $box;
|
||||
}
|
||||
|
||||
private function buildClusterStatusPanel() {
|
||||
|
@ -231,21 +243,9 @@ final class DiffusionRepositoryStorageManagementPanel
|
|||
'date',
|
||||
));
|
||||
|
||||
$doc_href = PhabricatorEnv::getDoclink('Cluster: Repositories');
|
||||
|
||||
$header = id(new PHUIHeaderView())
|
||||
->setHeader(pht('Cluster Status'))
|
||||
->addActionLink(
|
||||
id(new PHUIButtonView())
|
||||
->setIcon('fa-book')
|
||||
->setHref($doc_href)
|
||||
->setTag('a')
|
||||
->setText(pht('Documentation')));
|
||||
|
||||
return id(new PHUIObjectBoxView())
|
||||
->setHeader($header)
|
||||
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
||||
->setTable($table);
|
||||
$box = $this->newBox(pht('Cluster Status'), null);
|
||||
$box->setTable($table);
|
||||
return $box;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -36,9 +36,10 @@ final class DiffusionRepositorySubversionManagementPanel
|
|||
);
|
||||
}
|
||||
|
||||
protected function buildManagementPanelActions() {
|
||||
public function buildManagementPanelCurtain() {
|
||||
$repository = $this->getRepository();
|
||||
$viewer = $this->getViewer();
|
||||
$action_list = $this->getNewActionList();
|
||||
|
||||
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
||||
$viewer,
|
||||
|
@ -47,14 +48,15 @@ final class DiffusionRepositorySubversionManagementPanel
|
|||
|
||||
$subversion_uri = $this->getEditPageURI();
|
||||
|
||||
return array(
|
||||
$action_list->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setIcon('fa-pencil')
|
||||
->setName(pht('Edit Properties'))
|
||||
->setHref($subversion_uri)
|
||||
->setDisabled(!$can_edit)
|
||||
->setWorkflow(!$can_edit),
|
||||
);
|
||||
->setWorkflow(!$can_edit));
|
||||
|
||||
return $this->getNewCurtainView($action_list);
|
||||
}
|
||||
|
||||
public function buildManagementPanelContent() {
|
||||
|
@ -62,8 +64,7 @@ final class DiffusionRepositorySubversionManagementPanel
|
|||
$viewer = $this->getViewer();
|
||||
|
||||
$view = id(new PHUIPropertyListView())
|
||||
->setViewer($viewer)
|
||||
->setActionList($this->newActions());
|
||||
->setViewer($viewer);
|
||||
|
||||
$default_branch = nonempty(
|
||||
$repository->getHumanReadableDetail('svn-subpath'),
|
||||
|
|
|
@ -34,9 +34,10 @@ final class DiffusionRepositorySymbolsManagementPanel
|
|||
);
|
||||
}
|
||||
|
||||
protected function buildManagementPanelActions() {
|
||||
public function buildManagementPanelCurtain() {
|
||||
$repository = $this->getRepository();
|
||||
$viewer = $this->getViewer();
|
||||
$action_list = $this->getNewActionList();
|
||||
|
||||
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
||||
$viewer,
|
||||
|
@ -45,14 +46,15 @@ final class DiffusionRepositorySymbolsManagementPanel
|
|||
|
||||
$symbols_uri = $this->getEditPageURI();
|
||||
|
||||
return array(
|
||||
$action_list->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setIcon('fa-pencil')
|
||||
->setName(pht('Edit Symbols'))
|
||||
->setHref($symbols_uri)
|
||||
->setDisabled(!$can_edit)
|
||||
->setWorkflow(!$can_edit),
|
||||
);
|
||||
->setWorkflow(!$can_edit));
|
||||
|
||||
return $this->getNewCurtainView($action_list);
|
||||
}
|
||||
|
||||
public function buildManagementPanelContent() {
|
||||
|
@ -60,8 +62,7 @@ final class DiffusionRepositorySymbolsManagementPanel
|
|||
$viewer = $this->getViewer();
|
||||
|
||||
$view = id(new PHUIPropertyListView())
|
||||
->setViewer($viewer)
|
||||
->setActionList($this->newActions());
|
||||
->setViewer($viewer);
|
||||
|
||||
$languages = $repository->getSymbolLanguages();
|
||||
if ($languages) {
|
||||
|
|
|
@ -17,6 +17,35 @@ final class DiffusionRepositoryURIsManagementPanel
|
|||
return 400;
|
||||
}
|
||||
|
||||
public function buildManagementPanelCurtain() {
|
||||
$repository = $this->getRepository();
|
||||
$viewer = $this->getViewer();
|
||||
$action_list = $this->getNewActionList();
|
||||
|
||||
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
||||
$viewer,
|
||||
$repository,
|
||||
PhabricatorPolicyCapability::CAN_EDIT);
|
||||
|
||||
$doc_href = PhabricatorEnv::getDoclink('Diffusion User Guide: URIs');
|
||||
$add_href = $repository->getPathURI('uri/edit/');
|
||||
|
||||
$action_list->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setIcon('fa-plus')
|
||||
->setHref($add_href)
|
||||
->setDisabled(!$can_edit)
|
||||
->setName(pht('Add New URI')));
|
||||
|
||||
$action_list->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setIcon('fa-book')
|
||||
->setHref($doc_href)
|
||||
->setName(pht('URI Documentation')));
|
||||
|
||||
return $this->getNewCurtainView($action_list);
|
||||
}
|
||||
|
||||
public function buildManagementPanelContent() {
|
||||
$repository = $this->getRepository();
|
||||
$viewer = $this->getViewer();
|
||||
|
@ -95,24 +124,6 @@ final class DiffusionRepositoryURIsManagementPanel
|
|||
null,
|
||||
));
|
||||
|
||||
$doc_href = PhabricatorEnv::getDoclink('Diffusion User Guide: URIs');
|
||||
$add_href = $repository->getPathURI('uri/edit/');
|
||||
|
||||
$header = id(new PHUIHeaderView())
|
||||
->setHeader(pht('Repository URIs'))
|
||||
->addActionLink(
|
||||
id(new PHUIButtonView())
|
||||
->setIcon('fa-plus')
|
||||
->setHref($add_href)
|
||||
->setTag('a')
|
||||
->setText(pht('Add New URI')))
|
||||
->addActionLink(
|
||||
id(new PHUIButtonView())
|
||||
->setIcon('fa-book')
|
||||
->setHref($doc_href)
|
||||
->setTag('a')
|
||||
->setText(pht('Documentation')));
|
||||
|
||||
$is_new = $repository->isNewlyInitialized();
|
||||
|
||||
$messages = array();
|
||||
|
@ -123,11 +134,7 @@ final class DiffusionRepositoryURIsManagementPanel
|
|||
$host_message = pht('Phabricator is hosting this repository.');
|
||||
}
|
||||
|
||||
$messages[] = array(
|
||||
id(new PHUIIconView())->setIcon('fa-folder'),
|
||||
' ',
|
||||
$host_message,
|
||||
);
|
||||
$messages[] = $host_message;
|
||||
} else {
|
||||
if ($is_new) {
|
||||
$observe_message = pht(
|
||||
|
@ -137,22 +144,17 @@ final class DiffusionRepositoryURIsManagementPanel
|
|||
'This repository is hosted remotely. Phabricator is observing it.');
|
||||
}
|
||||
|
||||
$messages[] = array(
|
||||
id(new PHUIIconView())->setIcon('fa-download'),
|
||||
' ',
|
||||
$observe_message,
|
||||
);
|
||||
$messages[] = $observe_message;
|
||||
}
|
||||
|
||||
$info_view = id(new PHUIInfoView())
|
||||
->setSeverity(PHUIInfoView::SEVERITY_NOTICE)
|
||||
->setErrors($messages);
|
||||
|
||||
return id(new PHUIObjectBoxView())
|
||||
->setHeader($header)
|
||||
->setInfoView($info_view)
|
||||
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
||||
->setTable($table);
|
||||
$box = $this->newBox(pht('Repository URIs'), null);
|
||||
$box->setTable($table);
|
||||
|
||||
return array($info_view, $box);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
160
src/applications/diffusion/view/DiffusionCommitListView.php
Normal file
160
src/applications/diffusion/view/DiffusionCommitListView.php
Normal file
|
@ -0,0 +1,160 @@
|
|||
<?php
|
||||
|
||||
final class DiffusionCommitListView extends AphrontView {
|
||||
|
||||
private $commits = array();
|
||||
private $noDataString;
|
||||
|
||||
public function setNoDataString($no_data_string) {
|
||||
$this->noDataString = $no_data_string;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setHeader($header) {
|
||||
$this->header = $header;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setCommits(array $commits) {
|
||||
assert_instances_of($commits, 'PhabricatorRepositoryCommit');
|
||||
$this->commits = mpull($commits, null, 'getPHID');
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCommits() {
|
||||
return $this->commits;
|
||||
}
|
||||
|
||||
private function getCommitDescription($phid) {
|
||||
if ($this->commits === null) {
|
||||
return pht('(Unknown Commit)');
|
||||
}
|
||||
|
||||
$commit = idx($this->commits, $phid);
|
||||
if (!$commit) {
|
||||
return pht('(Unknown Commit)');
|
||||
}
|
||||
|
||||
$summary = $commit->getCommitData()->getSummary();
|
||||
if (strlen($summary)) {
|
||||
return $summary;
|
||||
}
|
||||
|
||||
// No summary, so either this is still importing or just has an empty
|
||||
// commit message.
|
||||
|
||||
if (!$commit->isImported()) {
|
||||
return pht('(Importing Commit...)');
|
||||
} else {
|
||||
return pht('(Untitled Commit)');
|
||||
}
|
||||
}
|
||||
|
||||
public function render() {
|
||||
require_celerity_resource('diffusion-history-css');
|
||||
return $this->buildList();
|
||||
}
|
||||
|
||||
public function buildList() {
|
||||
$viewer = $this->getViewer();
|
||||
$rowc = array();
|
||||
|
||||
$phids = array();
|
||||
foreach ($this->getCommits() as $commit) {
|
||||
$phids[] = $commit->getPHID();
|
||||
|
||||
$author_phid = $commit->getAuthorPHID();
|
||||
if ($author_phid) {
|
||||
$phids[] = $author_phid;
|
||||
}
|
||||
}
|
||||
|
||||
$handles = $viewer->loadHandles($phids);
|
||||
|
||||
$cur_date = 0;
|
||||
$list = null;
|
||||
$header = null;
|
||||
$view = array();
|
||||
foreach ($this->commits as $commit) {
|
||||
$new_date = date('Ymd', $commit->getEpoch());
|
||||
if ($cur_date != $new_date) {
|
||||
if ($list) {
|
||||
$view[] = id(new PHUIObjectBoxView())
|
||||
->setHeader($header)
|
||||
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
||||
->setObjectList($list);
|
||||
}
|
||||
$date = ucfirst(
|
||||
phabricator_relative_date($commit->getEpoch(), $viewer));
|
||||
$header = id(new PHUIHeaderView())
|
||||
->setHeader($date);
|
||||
$list = id(new PHUIObjectItemListView())
|
||||
->setFlush(true)
|
||||
->addClass('diffusion-history-list');
|
||||
}
|
||||
|
||||
$commit_phid = $commit->getPHID();
|
||||
$commit_handle = $handles[$commit_phid];
|
||||
$committed = null;
|
||||
|
||||
$commit_name = $commit_handle->getName();
|
||||
$commit_link = $commit_handle->getURI();
|
||||
$commit_desc = $this->getCommitDescription($commit_phid);
|
||||
$committed = phabricator_datetime($commit->getEpoch(), $viewer);
|
||||
|
||||
$engine = PhabricatorMarkupEngine::newDifferentialMarkupEngine();
|
||||
$engine->setConfig('viewer', $viewer);
|
||||
$commit_data = $commit->getCommitData();
|
||||
$message = $commit_data->getCommitMessage();
|
||||
$message = $engine->markupText($message);
|
||||
$message = phutil_tag_div(
|
||||
'diffusion-history-message phabricator-remarkup', $message);
|
||||
|
||||
$author_phid = $commit->getAuthorPHID();
|
||||
if ($author_phid) {
|
||||
$author_name = $handles[$author_phid]->renderLink();
|
||||
$author_image_uri = $handles[$author_phid]->getImageURI();
|
||||
$author_image_href = $handles[$author_phid]->getURI();
|
||||
} else {
|
||||
$author_name = $commit->getCommitData()->getAuthorName();
|
||||
$author_image_uri =
|
||||
celerity_get_resource_uri('/rsrc/image/people/user0.png');
|
||||
$author_image_href = null;
|
||||
}
|
||||
|
||||
$commit_tag = id(new PHUITagView())
|
||||
->setName($commit_name)
|
||||
->setType(PHUITagView::TYPE_SHADE)
|
||||
->setColor(PHUITagView::COLOR_INDIGO)
|
||||
->setSlimShady(true);
|
||||
|
||||
$item = id(new PHUIObjectItemView())
|
||||
->setHeader($commit_desc)
|
||||
->setHref($commit_link)
|
||||
->setDisabled($commit->isUnreachable())
|
||||
->setDescription($message)
|
||||
->setImageURI($author_image_uri)
|
||||
->setImageHref($author_image_href)
|
||||
->addByline(pht('Author: %s', $author_name))
|
||||
->addIcon('none', $committed)
|
||||
->addAttribute($commit_tag);
|
||||
|
||||
$list->addItem($item);
|
||||
$cur_date = $new_date;
|
||||
}
|
||||
|
||||
if (!$view) {
|
||||
$list = id(new PHUIObjectItemListView())
|
||||
->setFlush(true)
|
||||
->setNoDataString($this->noDataString);
|
||||
|
||||
$view = id(new PHUIObjectBoxView())
|
||||
->setHeaderText(pht('Recent Commits'))
|
||||
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
||||
->setObjectList($list);
|
||||
}
|
||||
|
||||
return $view;
|
||||
}
|
||||
|
||||
}
|
|
@ -67,16 +67,16 @@ final class FeedQueryConduitAPIMethod extends FeedConduitAPIMethod {
|
|||
if (!$limit) {
|
||||
$limit = $this->getDefaultLimit();
|
||||
}
|
||||
$filter_phids = $request->getValue('filterPHIDs');
|
||||
if (!$filter_phids) {
|
||||
$filter_phids = array();
|
||||
}
|
||||
|
||||
$query = id(new PhabricatorFeedQuery())
|
||||
->setLimit($limit)
|
||||
->setFilterPHIDs($filter_phids)
|
||||
->setViewer($user);
|
||||
|
||||
$filter_phids = $request->getValue('filterPHIDs');
|
||||
if ($filter_phids) {
|
||||
$query->withFilterPHIDs($filter_phids);
|
||||
}
|
||||
|
||||
$after = $request->getValue('after');
|
||||
if (strlen($after)) {
|
||||
$query->setAfterID($after);
|
||||
|
|
|
@ -5,8 +5,10 @@ final class PhabricatorFeedQuery
|
|||
|
||||
private $filterPHIDs;
|
||||
private $chronologicalKeys;
|
||||
private $rangeMin;
|
||||
private $rangeMax;
|
||||
|
||||
public function setFilterPHIDs(array $phids) {
|
||||
public function withFilterPHIDs(array $phids) {
|
||||
$this->filterPHIDs = $phids;
|
||||
return $this;
|
||||
}
|
||||
|
@ -16,50 +18,52 @@ final class PhabricatorFeedQuery
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function withEpochInRange($range_min, $range_max) {
|
||||
$this->rangeMin = $range_min;
|
||||
$this->rangeMax = $range_max;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function newResultObject() {
|
||||
return new PhabricatorFeedStoryData();
|
||||
}
|
||||
|
||||
protected function loadPage() {
|
||||
$story_table = new PhabricatorFeedStoryData();
|
||||
$conn = $story_table->establishConnection('r');
|
||||
|
||||
$data = queryfx_all(
|
||||
$conn,
|
||||
'SELECT story.* FROM %T story %Q %Q %Q %Q %Q',
|
||||
$story_table->getTableName(),
|
||||
$this->buildJoinClause($conn),
|
||||
$this->buildWhereClause($conn),
|
||||
$this->buildGroupClause($conn),
|
||||
$this->buildOrderClause($conn),
|
||||
$this->buildLimitClause($conn));
|
||||
|
||||
return $data;
|
||||
// NOTE: We return raw rows from this method, which is a little unusual.
|
||||
return $this->loadStandardPageRows($this->newResultObject());
|
||||
}
|
||||
|
||||
protected function willFilterPage(array $data) {
|
||||
return PhabricatorFeedStory::loadAllFromRows($data, $this->getViewer());
|
||||
}
|
||||
|
||||
protected function buildJoinClause(AphrontDatabaseConnection $conn_r) {
|
||||
protected function buildJoinClauseParts(AphrontDatabaseConnection $conn) {
|
||||
$joins = parent::buildJoinClauseParts($conn);
|
||||
|
||||
// NOTE: We perform this join unconditionally (even if we have no filter
|
||||
// PHIDs) to omit rows which have no story references. These story data
|
||||
// rows are notifications or realtime alerts.
|
||||
|
||||
$ref_table = new PhabricatorFeedStoryReference();
|
||||
return qsprintf(
|
||||
$conn_r,
|
||||
$joins[] = qsprintf(
|
||||
$conn,
|
||||
'JOIN %T ref ON ref.chronologicalKey = story.chronologicalKey',
|
||||
$ref_table->getTableName());
|
||||
|
||||
return $joins;
|
||||
}
|
||||
|
||||
protected function buildWhereClause(AphrontDatabaseConnection $conn_r) {
|
||||
$where = array();
|
||||
protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
|
||||
$where = parent::buildWhereClauseParts($conn);
|
||||
|
||||
if ($this->filterPHIDs) {
|
||||
if ($this->filterPHIDs !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
$conn,
|
||||
'ref.objectPHID IN (%Ls)',
|
||||
$this->filterPHIDs);
|
||||
}
|
||||
|
||||
if ($this->chronologicalKeys) {
|
||||
if ($this->chronologicalKeys !== null) {
|
||||
// NOTE: We want to use integers in the query so we can take advantage
|
||||
// of keys, but can't use %d on 32-bit systems. Make sure all the keys
|
||||
// are integers and then format them raw.
|
||||
|
@ -73,21 +77,37 @@ final class PhabricatorFeedQuery
|
|||
}
|
||||
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
$conn,
|
||||
'ref.chronologicalKey IN (%Q)',
|
||||
implode(', ', $keys));
|
||||
}
|
||||
|
||||
$where[] = $this->buildPagingClause($conn_r);
|
||||
// NOTE: We may not have 64-bit PHP, so do the shifts in MySQL instead.
|
||||
// From EXPLAIN, it appears like MySQL is smart enough to compute the
|
||||
// result and make use of keys to execute the query.
|
||||
|
||||
return $this->formatWhereClause($where);
|
||||
if ($this->rangeMin !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'ref.chronologicalKey >= (%d << 32)',
|
||||
$this->rangeMin);
|
||||
}
|
||||
|
||||
if ($this->rangeMax !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'ref.chronologicalKey < (%d << 32)',
|
||||
$this->rangeMax);
|
||||
}
|
||||
|
||||
return $where;
|
||||
}
|
||||
|
||||
protected function buildGroupClause(AphrontDatabaseConnection $conn_r) {
|
||||
if ($this->filterPHIDs) {
|
||||
return qsprintf($conn_r, 'GROUP BY ref.chronologicalKey');
|
||||
protected function buildGroupClause(AphrontDatabaseConnection $conn) {
|
||||
if ($this->filterPHIDs !== null) {
|
||||
return qsprintf($conn, 'GROUP BY ref.chronologicalKey');
|
||||
} else {
|
||||
return qsprintf($conn_r, 'GROUP BY story.chronologicalKey');
|
||||
return qsprintf($conn, 'GROUP BY story.chronologicalKey');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -95,6 +115,20 @@ final class PhabricatorFeedQuery
|
|||
return array('key');
|
||||
}
|
||||
|
||||
public function getBuiltinOrders() {
|
||||
return array(
|
||||
'newest' => array(
|
||||
'vector' => array('key'),
|
||||
'name' => pht('Creation (Newest First)'),
|
||||
'aliases' => array('created'),
|
||||
),
|
||||
'oldest' => array(
|
||||
'vector' => array('-key'),
|
||||
'name' => pht('Creation (Oldest First)'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
public function getOrderableColumns() {
|
||||
$table = ($this->filterPHIDs ? 'ref' : 'story');
|
||||
return array(
|
||||
|
@ -120,6 +154,10 @@ final class PhabricatorFeedQuery
|
|||
return $item['chronologicalKey'];
|
||||
}
|
||||
|
||||
protected function getPrimaryTableAlias() {
|
||||
return 'story';
|
||||
}
|
||||
|
||||
public function getQueryApplicationClass() {
|
||||
return 'PhabricatorFeedApplication';
|
||||
}
|
||||
|
|
|
@ -11,87 +11,99 @@ final class PhabricatorFeedSearchEngine
|
|||
return 'PhabricatorFeedApplication';
|
||||
}
|
||||
|
||||
public function buildSavedQueryFromRequest(AphrontRequest $request) {
|
||||
$saved = new PhabricatorSavedQuery();
|
||||
|
||||
$saved->setParameter(
|
||||
'userPHIDs',
|
||||
$this->readUsersFromRequest($request, 'users'));
|
||||
|
||||
$saved->setParameter(
|
||||
'projectPHIDs',
|
||||
array_values($request->getArr('projectPHIDs')));
|
||||
|
||||
$saved->setParameter(
|
||||
'viewerProjects',
|
||||
$request->getBool('viewerProjects'));
|
||||
|
||||
return $saved;
|
||||
public function newQuery() {
|
||||
return new PhabricatorFeedQuery();
|
||||
}
|
||||
|
||||
public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) {
|
||||
$query = id(new PhabricatorFeedQuery());
|
||||
protected function shouldShowOrderField() {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function buildCustomSearchFields() {
|
||||
return array(
|
||||
id(new PhabricatorUsersSearchField())
|
||||
->setLabel(pht('Include Users'))
|
||||
->setKey('userPHIDs'),
|
||||
// NOTE: This query is not executed with EdgeLogic, so we can't use
|
||||
// a fancy logical datasource.
|
||||
id(new PhabricatorSearchDatasourceField())
|
||||
->setDatasource(new PhabricatorProjectDatasource())
|
||||
->setLabel(pht('Include Projects'))
|
||||
->setKey('projectPHIDs'),
|
||||
id(new PhabricatorSearchDateControlField())
|
||||
->setLabel(pht('Occurs After'))
|
||||
->setKey('rangeStart'),
|
||||
id(new PhabricatorSearchDateControlField())
|
||||
->setLabel(pht('Occurs Before'))
|
||||
->setKey('rangeEnd'),
|
||||
|
||||
// NOTE: This is a legacy field retained only for backward
|
||||
// compatibility. If the projects field used EdgeLogic, we could use
|
||||
// `viewerprojects()` to execute an equivalent query.
|
||||
id(new PhabricatorSearchCheckboxesField())
|
||||
->setKey('viewerProjects')
|
||||
->setOptions(
|
||||
array(
|
||||
'self' => pht('Include stories about projects I am a member of.'),
|
||||
)),
|
||||
);
|
||||
}
|
||||
|
||||
protected function buildQueryFromParameters(array $map) {
|
||||
$query = $this->newQuery();
|
||||
|
||||
$phids = array();
|
||||
|
||||
$user_phids = $saved->getParameter('userPHIDs');
|
||||
if ($user_phids) {
|
||||
$phids[] = $user_phids;
|
||||
if ($map['userPHIDs']) {
|
||||
$phids += array_fuse($map['userPHIDs']);
|
||||
}
|
||||
|
||||
$proj_phids = $saved->getParameter('projectPHIDs');
|
||||
if ($proj_phids) {
|
||||
$phids[] = $proj_phids;
|
||||
if ($map['projectPHIDs']) {
|
||||
$phids += array_fuse($map['projectPHIDs']);
|
||||
}
|
||||
|
||||
$viewer_projects = $saved->getParameter('viewerProjects');
|
||||
// NOTE: This value may be `true` for older saved queries, or
|
||||
// `array('self')` for newer ones.
|
||||
$viewer_projects = $map['viewerProjects'];
|
||||
if ($viewer_projects) {
|
||||
$viewer = $this->requireViewer();
|
||||
$projects = id(new PhabricatorProjectQuery())
|
||||
->setViewer($viewer)
|
||||
->withMemberPHIDs(array($viewer->getPHID()))
|
||||
->execute();
|
||||
$phids[] = mpull($projects, 'getPHID');
|
||||
$phids += array_fuse(mpull($projects, 'getPHID'));
|
||||
}
|
||||
|
||||
$phids = array_mergev($phids);
|
||||
if ($phids) {
|
||||
$query->setFilterPHIDs($phids);
|
||||
$query->withFilterPHIDs($phids);
|
||||
}
|
||||
|
||||
$range_min = $map['rangeStart'];
|
||||
if ($range_min) {
|
||||
$range_min = $range_min->getEpoch();
|
||||
}
|
||||
|
||||
$range_max = $map['rangeEnd'];
|
||||
if ($range_max) {
|
||||
$range_max = $range_max->getEpoch();
|
||||
}
|
||||
|
||||
if ($range_min && $range_max) {
|
||||
if ($range_min > $range_max) {
|
||||
throw new PhabricatorSearchConstraintException(
|
||||
pht(
|
||||
'The specified "Occurs Before" date is earlier in time than the '.
|
||||
'specified "Occurs After" date, so this query can never match '.
|
||||
'any results.'));
|
||||
}
|
||||
}
|
||||
|
||||
if ($range_min || $range_max) {
|
||||
$query->withEpochInRange($range_min, $range_max);
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
public function buildSearchForm(
|
||||
AphrontFormView $form,
|
||||
PhabricatorSavedQuery $saved_query) {
|
||||
|
||||
$user_phids = $saved_query->getParameter('userPHIDs', array());
|
||||
$proj_phids = $saved_query->getParameter('projectPHIDs', array());
|
||||
$viewer_projects = $saved_query->getParameter('viewerProjects');
|
||||
|
||||
$form
|
||||
->appendControl(
|
||||
id(new AphrontFormTokenizerControl())
|
||||
->setDatasource(new PhabricatorPeopleDatasource())
|
||||
->setName('users')
|
||||
->setLabel(pht('Include Users'))
|
||||
->setValue($user_phids))
|
||||
->appendControl(
|
||||
id(new AphrontFormTokenizerControl())
|
||||
->setDatasource(new PhabricatorProjectDatasource())
|
||||
->setName('projectPHIDs')
|
||||
->setLabel(pht('Include Projects'))
|
||||
->setValue($proj_phids))
|
||||
->appendChild(
|
||||
id(new AphrontFormCheckboxControl())
|
||||
->addCheckbox(
|
||||
'viewerProjects',
|
||||
1,
|
||||
pht('Include stories about projects I am a member of.'),
|
||||
$viewer_projects));
|
||||
}
|
||||
|
||||
protected function getURI($path) {
|
||||
return '/feed/'.$path;
|
||||
}
|
||||
|
@ -117,7 +129,7 @@ final class PhabricatorFeedSearchEngine
|
|||
case 'all':
|
||||
return $query;
|
||||
case 'projects':
|
||||
return $query->setParameter('viewerProjects', true);
|
||||
return $query->setParameter('viewerProjects', array('self'));
|
||||
}
|
||||
|
||||
return parent::buildSavedQueryFromBuiltin($query_key);
|
||||
|
|
|
@ -44,7 +44,7 @@ final class PhabricatorFileInfoController extends PhabricatorFileController {
|
|||
if ($ttl !== null) {
|
||||
$ttl_tag = id(new PHUITagView())
|
||||
->setType(PHUITagView::TYPE_SHADE)
|
||||
->setShade(PHUITagView::COLOR_YELLOW)
|
||||
->setColor(PHUITagView::COLOR_YELLOW)
|
||||
->setName(pht('Temporary'));
|
||||
$header->addTag($ttl_tag);
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ final class PhabricatorFileInfoController extends PhabricatorFileController {
|
|||
if ($partial) {
|
||||
$partial_tag = id(new PHUITagView())
|
||||
->setType(PHUITagView::TYPE_SHADE)
|
||||
->setShade(PHUITagView::COLOR_ORANGE)
|
||||
->setColor(PHUITagView::COLOR_ORANGE)
|
||||
->setName(pht('Partial Upload'));
|
||||
$header->addTag($partial_tag);
|
||||
}
|
||||
|
|
|
@ -30,8 +30,8 @@ final class PhabricatorGuideListView extends AphrontView {
|
|||
->setText(pht('Skip'))
|
||||
->setTag('a')
|
||||
->setHref($skip_href)
|
||||
->setColor(PHUIButtonView::GREY);
|
||||
$list_item->setLaunchButton($skip);
|
||||
->setColor(PHUIButtonView::SIMPLE);
|
||||
$list_item->setSideColumn($skip);
|
||||
}
|
||||
$list->addItem($list_item);
|
||||
}
|
||||
|
|
|
@ -56,7 +56,7 @@ final class HarbormasterUnitSummaryView extends AphrontView {
|
|||
|
||||
$tag = id(new PHUITagView())
|
||||
->setType(PHUITagView::TYPE_SHADE)
|
||||
->setShade($tag_color)
|
||||
->setColor($tag_color)
|
||||
->setIcon($tag_icon)
|
||||
->setName($tag_text);
|
||||
|
||||
|
|
|
@ -125,6 +125,34 @@ final class ManiphestTaskTestCase extends PhabricatorTestCase {
|
|||
9,
|
||||
count($subpri),
|
||||
pht('Expected subpriorities to be distributed.'));
|
||||
|
||||
// Move task 9 to the end.
|
||||
$this->moveTask($viewer, $t[9], $t[1], true);
|
||||
$tasks = $this->loadTasks($viewer, $auto_base);
|
||||
$this->assertEqual(
|
||||
array(8, 7, 6, 5, 4, 3, 2, 1, 9),
|
||||
array_keys($tasks));
|
||||
|
||||
// Move task 3 to the beginning.
|
||||
$this->moveTask($viewer, $t[3], $t[8], false);
|
||||
$tasks = $this->loadTasks($viewer, $auto_base);
|
||||
$this->assertEqual(
|
||||
array(3, 8, 7, 6, 5, 4, 2, 1, 9),
|
||||
array_keys($tasks));
|
||||
|
||||
// Move task 3 to the end.
|
||||
$this->moveTask($viewer, $t[3], $t[9], true);
|
||||
$tasks = $this->loadTasks($viewer, $auto_base);
|
||||
$this->assertEqual(
|
||||
array(8, 7, 6, 5, 4, 2, 1, 9, 3),
|
||||
array_keys($tasks));
|
||||
|
||||
// Move task 5 to before task 4 (this is its current position).
|
||||
$this->moveTask($viewer, $t[5], $t[4], false);
|
||||
$tasks = $this->loadTasks($viewer, $auto_base);
|
||||
$this->assertEqual(
|
||||
array(8, 7, 6, 5, 4, 2, 1, 9, 3),
|
||||
array_keys($tasks));
|
||||
}
|
||||
|
||||
private function newTask(PhabricatorUser $viewer, $title) {
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
final class ManiphestPrioritySearchConduitAPIMethod
|
||||
extends ManiphestConduitAPIMethod {
|
||||
|
||||
public function getAPIMethodName() {
|
||||
return 'maniphest.priority.search';
|
||||
}
|
||||
|
||||
public function getMethodSummary() {
|
||||
return pht('Read information about task priorities.');
|
||||
}
|
||||
|
||||
public function getMethodDescription() {
|
||||
return pht(
|
||||
'Returns information about the possible priorities for Maniphest '.
|
||||
'tasks.');
|
||||
}
|
||||
|
||||
protected function defineParamTypes() {
|
||||
return array();
|
||||
}
|
||||
|
||||
protected function defineReturnType() {
|
||||
return 'map<string, wild>';
|
||||
}
|
||||
|
||||
public function getRequiredScope() {
|
||||
return self::SCOPE_ALWAYS;
|
||||
}
|
||||
|
||||
protected function execute(ConduitAPIRequest $request) {
|
||||
$config = ManiphestTaskPriority::getConfig();
|
||||
|
||||
$results = array();
|
||||
foreach ($config as $code => $priority) {
|
||||
$priority['value'] = $code;
|
||||
$results[] = $priority;
|
||||
}
|
||||
|
||||
return array('data' => $results);
|
||||
}
|
||||
|
||||
}
|
|
@ -335,9 +335,16 @@ dictionary with these keys:
|
|||
"task", "feature", or "bug".
|
||||
- `name` //Required string.// Human-readable name for this subtype, like
|
||||
"Task", "Feature Request" or "Bug Report".
|
||||
- `tag` //Optional string.// Tag text for this subtype.
|
||||
- `color` //Optional string.// Display color for this subtype.
|
||||
- `icon` //Optional string.// Icon for the subtype.
|
||||
|
||||
Each subtype must have a unique key, and you must define a subtype with
|
||||
the key "%s", which is used as a default subtype.
|
||||
|
||||
The tag text (`tag`) is used to set the text shown in the subtype tag on list
|
||||
views and workboards. If you do not configure it, the default subtype will have
|
||||
no subtype tag and other subtypes will use their name as tag text.
|
||||
EOTEXT
|
||||
,
|
||||
$subtype_default_key));
|
||||
|
|
|
@ -110,7 +110,7 @@ final class ManiphestTaskPriority extends ManiphestConstants {
|
|||
return idx($config, 'disabled', false);
|
||||
}
|
||||
|
||||
private static function getConfig() {
|
||||
public static function getConfig() {
|
||||
$config = PhabricatorEnv::getEnvConfig('maniphest.priorities');
|
||||
krsort($config);
|
||||
return $config;
|
||||
|
|
|
@ -97,7 +97,7 @@ final class ManiphestTaskStatus extends ManiphestConstants {
|
|||
->setName($name)
|
||||
->setIcon($icon)
|
||||
->setType(PHUITagView::TYPE_SHADE)
|
||||
->setShade($color);
|
||||
->setColor($color);
|
||||
|
||||
return $tag;
|
||||
}
|
||||
|
|
|
@ -233,13 +233,19 @@ final class ManiphestTaskDetailController extends ManiphestController {
|
|||
ManiphestTaskPoints::getPointsLabel());
|
||||
$tag = id(new PHUITagView())
|
||||
->setName($points_name)
|
||||
->setShade('blue')
|
||||
->setColor(PHUITagView::COLOR_BLUE)
|
||||
->setType(PHUITagView::TYPE_SHADE);
|
||||
|
||||
$view->addTag($tag);
|
||||
}
|
||||
}
|
||||
|
||||
$subtype = $task->newSubtypeObject();
|
||||
if ($subtype && $subtype->hasTagView()) {
|
||||
$subtype_tag = $subtype->newTagView();
|
||||
$view->addTag($subtype_tag);
|
||||
}
|
||||
|
||||
return $view;
|
||||
}
|
||||
|
||||
|
|
|
@ -384,8 +384,7 @@ final class ManiphestTransactionEditor
|
|||
*/
|
||||
public static function getAdjacentSubpriority(
|
||||
ManiphestTask $dst,
|
||||
$is_after,
|
||||
$allow_recursion = true) {
|
||||
$is_after) {
|
||||
|
||||
$query = id(new ManiphestTaskQuery())
|
||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||
|
@ -407,76 +406,25 @@ final class ManiphestTransactionEditor
|
|||
// If we find an adjacent task, we average the two subpriorities and
|
||||
// return the result.
|
||||
if ($adjacent) {
|
||||
$epsilon = 0.01;
|
||||
$epsilon = 1.0;
|
||||
|
||||
// If the adjacent task has a subpriority that is identical or very
|
||||
// close to the task we're looking at, we're going to move it and all
|
||||
// tasks with the same subpriority a little farther down the subpriority
|
||||
// scale.
|
||||
if ($allow_recursion &&
|
||||
(abs($adjacent->getSubpriority() - $base) < $epsilon)) {
|
||||
$conn_w = $adjacent->establishConnection('w');
|
||||
// close to the task we're looking at, we're going to spread out all
|
||||
// the nearby tasks.
|
||||
|
||||
$min = ($adjacent->getSubpriority() - ($epsilon));
|
||||
$max = ($adjacent->getSubpriority() + ($epsilon));
|
||||
|
||||
// Get all of the tasks with the similar subpriorities to the adjacent
|
||||
// task, including the adjacent task itself.
|
||||
$query = id(new ManiphestTaskQuery())
|
||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||
->withPriorities(array($adjacent->getPriority()))
|
||||
->withSubpriorityBetween($min, $max);
|
||||
|
||||
if (!$is_after) {
|
||||
$query->setOrderVector(array('-priority', '-subpriority', '-id'));
|
||||
$adjacent_sub = $adjacent->getSubpriority();
|
||||
if ((abs($adjacent_sub - $base) < $epsilon)) {
|
||||
$base = self::disperseBlock(
|
||||
$dst,
|
||||
$epsilon * 2);
|
||||
if ($is_after) {
|
||||
$sub = $base - $epsilon;
|
||||
} else {
|
||||
$query->setOrderVector(array('priority', 'subpriority', 'id'));
|
||||
}
|
||||
|
||||
$shift_all = $query->execute();
|
||||
$shift_last = last($shift_all);
|
||||
|
||||
// Select the most extreme subpriority in the result set as the
|
||||
// base value.
|
||||
$shift_base = head($shift_all)->getSubpriority();
|
||||
|
||||
// Find the subpriority before or after the task at the end of the
|
||||
// block.
|
||||
list($shift_pri, $shift_sub) = self::getAdjacentSubpriority(
|
||||
$shift_last,
|
||||
$is_after,
|
||||
$allow_recursion = false);
|
||||
|
||||
$delta = ($shift_sub - $shift_base);
|
||||
$count = count($shift_all);
|
||||
|
||||
$shift = array();
|
||||
$cursor = 1;
|
||||
foreach ($shift_all as $shift_task) {
|
||||
$shift_target = $shift_base + (($cursor / $count) * $delta);
|
||||
$cursor++;
|
||||
|
||||
queryfx(
|
||||
$conn_w,
|
||||
'UPDATE %T SET subpriority = %f WHERE id = %d',
|
||||
$adjacent->getTableName(),
|
||||
$shift_target,
|
||||
$shift_task->getID());
|
||||
|
||||
// If we're shifting the adjacent task, update it.
|
||||
if ($shift_task->getID() == $adjacent->getID()) {
|
||||
$adjacent->setSubpriority($shift_target);
|
||||
}
|
||||
|
||||
// If we're shifting the original target task, update the base
|
||||
// subpriority.
|
||||
if ($shift_task->getID() == $dst->getID()) {
|
||||
$base = $shift_target;
|
||||
}
|
||||
$sub = $base + $epsilon;
|
||||
}
|
||||
} else {
|
||||
$sub = ($adjacent_sub + $base) / 2;
|
||||
}
|
||||
|
||||
$sub = ($adjacent->getSubpriority() + $base) / 2;
|
||||
} else {
|
||||
// Otherwise, we take a step away from the target's subpriority and
|
||||
// use that.
|
||||
|
@ -490,6 +438,156 @@ final class ManiphestTransactionEditor
|
|||
return array($dst->getPriority(), $sub);
|
||||
}
|
||||
|
||||
/**
|
||||
* Distribute a cluster of tasks with similar subpriorities.
|
||||
*/
|
||||
private static function disperseBlock(
|
||||
ManiphestTask $task,
|
||||
$spacing) {
|
||||
|
||||
$conn = $task->establishConnection('w');
|
||||
|
||||
// Find a block of subpriority space which is, on average, sparse enough
|
||||
// to hold all the tasks that are inside it with a reasonable level of
|
||||
// separation between them.
|
||||
|
||||
// We'll start by looking near the target task for a range of numbers
|
||||
// which has more space available than tasks. For example, if the target
|
||||
// task has subpriority 33 and we want to separate each task by at least 1,
|
||||
// we might start by looking in the range [23, 43].
|
||||
|
||||
// If we find fewer than 20 tasks there, we have room to reassign them
|
||||
// with the desired level of separation. We space them out, then we're
|
||||
// done.
|
||||
|
||||
// However: if we find more than 20 tasks, we don't have enough room to
|
||||
// distribute them. We'll widen our search and look in a bigger range,
|
||||
// maybe [13, 53]. This range has more space, so if we find fewer than
|
||||
// 40 tasks in this range we can spread them out. If we still find too
|
||||
// many tasks, we keep widening the search.
|
||||
|
||||
$base = $task->getSubpriority();
|
||||
|
||||
$scale = 4.0;
|
||||
while (true) {
|
||||
$range = ($spacing * $scale) / 2.0;
|
||||
$min = ($base - $range);
|
||||
$max = ($base + $range);
|
||||
|
||||
$result = queryfx_one(
|
||||
$conn,
|
||||
'SELECT COUNT(*) N FROM %T WHERE priority = %d AND
|
||||
subpriority BETWEEN %f AND %f',
|
||||
$task->getTableName(),
|
||||
$task->getPriority(),
|
||||
$min,
|
||||
$max);
|
||||
|
||||
$count = $result['N'];
|
||||
if ($count < $scale) {
|
||||
// We have found a block which we can make sparse enough, so bail and
|
||||
// continue below with our selection.
|
||||
break;
|
||||
}
|
||||
|
||||
// This block had too many tasks for its size, so try again with a
|
||||
// bigger block.
|
||||
$scale *= 2.0;
|
||||
}
|
||||
|
||||
$rows = queryfx_all(
|
||||
$conn,
|
||||
'SELECT id FROM %T WHERE priority = %d AND
|
||||
subpriority BETWEEN %f AND %f
|
||||
ORDER BY priority, subpriority, id',
|
||||
$task->getTableName(),
|
||||
$task->getPriority(),
|
||||
$min,
|
||||
$max);
|
||||
|
||||
$task_id = $task->getID();
|
||||
$result = null;
|
||||
|
||||
// NOTE: In strict mode (which we encourage enabling) we can't structure
|
||||
// this bulk update as an "INSERT ... ON DUPLICATE KEY UPDATE" unless we
|
||||
// provide default values for ALL of the columns that don't have defaults.
|
||||
|
||||
// This is gross, but we may be moving enough rows that individual
|
||||
// queries are unreasonably slow. An alternate construction which might
|
||||
// be worth evaluating is to use "CASE". Another approach is to disable
|
||||
// strict mode for this query.
|
||||
|
||||
$extra_columns = array(
|
||||
'phid' => '""',
|
||||
'authorPHID' => '""',
|
||||
'status' => '""',
|
||||
'priority' => 0,
|
||||
'title' => '""',
|
||||
'originalTitle' => '""',
|
||||
'description' => '""',
|
||||
'dateCreated' => 0,
|
||||
'dateModified' => 0,
|
||||
'mailKey' => '""',
|
||||
'viewPolicy' => '""',
|
||||
'editPolicy' => '""',
|
||||
'ownerOrdering' => '""',
|
||||
'spacePHID' => '""',
|
||||
'bridgedObjectPHID' => '""',
|
||||
'properties' => '""',
|
||||
'points' => 0,
|
||||
'subtype' => '""',
|
||||
);
|
||||
|
||||
$defaults = implode(', ', $extra_columns);
|
||||
|
||||
$sql = array();
|
||||
$offset = 0;
|
||||
|
||||
// Often, we'll have more room than we need in the range. Distribute the
|
||||
// tasks evenly over the whole range so that we're less likely to end up
|
||||
// with tasks spaced exactly the minimum distance apart, which may
|
||||
// get shifted again later. We have one fewer space to distribute than we
|
||||
// have tasks.
|
||||
$divisor = (double)(count($rows) - 1.0);
|
||||
if ($divisor > 0) {
|
||||
$available_distance = (($max - $min) / $divisor);
|
||||
} else {
|
||||
$available_distance = 0.0;
|
||||
}
|
||||
|
||||
foreach ($rows as $row) {
|
||||
$subpriority = $min + ($offset * $available_distance);
|
||||
|
||||
// If this is the task that we're spreading out relative to, keep track
|
||||
// of where it is ending up so we can return the new subpriority.
|
||||
$id = $row['id'];
|
||||
if ($id == $task_id) {
|
||||
$result = $subpriority;
|
||||
}
|
||||
|
||||
$sql[] = qsprintf(
|
||||
$conn,
|
||||
'(%d, %Q, %f)',
|
||||
$id,
|
||||
$defaults,
|
||||
$subpriority);
|
||||
|
||||
$offset++;
|
||||
}
|
||||
|
||||
foreach (PhabricatorLiskDAO::chunkSQL($sql) as $chunk) {
|
||||
queryfx(
|
||||
$conn,
|
||||
'INSERT INTO %T (id, %Q, subpriority) VALUES %Q
|
||||
ON DUPLICATE KEY UPDATE subpriority = VALUES(subpriority)',
|
||||
$task->getTableName(),
|
||||
implode(', ', array_keys($extra_columns)),
|
||||
$chunk);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
protected function validateAllTransactions(
|
||||
PhabricatorLiskDAO $object,
|
||||
array $xactions) {
|
||||
|
|
|
@ -17,8 +17,6 @@ final class ManiphestTaskQuery extends PhabricatorCursorPagedPolicyAwareQuery {
|
|||
private $dateCreatedBefore;
|
||||
private $dateModifiedAfter;
|
||||
private $dateModifiedBefore;
|
||||
private $subpriorityMin;
|
||||
private $subpriorityMax;
|
||||
private $bridgedObjectPHIDs;
|
||||
private $hasOpenParents;
|
||||
private $hasOpenSubtasks;
|
||||
|
@ -112,12 +110,6 @@ final class ManiphestTaskQuery extends PhabricatorCursorPagedPolicyAwareQuery {
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function withSubpriorityBetween($min, $max) {
|
||||
$this->subpriorityMin = $min;
|
||||
$this->subpriorityMax = $max;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withSubscribers(array $subscribers) {
|
||||
$this->subscriberPHIDs = $subscribers;
|
||||
return $this;
|
||||
|
@ -408,20 +400,6 @@ final class ManiphestTaskQuery extends PhabricatorCursorPagedPolicyAwareQuery {
|
|||
$this->subpriorities);
|
||||
}
|
||||
|
||||
if ($this->subpriorityMin !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'task.subpriority >= %f',
|
||||
$this->subpriorityMin);
|
||||
}
|
||||
|
||||
if ($this->subpriorityMax !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'task.subpriority <= %f',
|
||||
$this->subpriorityMax);
|
||||
}
|
||||
|
||||
if ($this->bridgedObjectPHIDs !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
|
|
|
@ -540,6 +540,11 @@ final class ManiphestTask extends ManiphestDAO
|
|||
);
|
||||
}
|
||||
|
||||
public function newSubtypeObject() {
|
||||
$subtype_key = $this->getEditEngineSubtype();
|
||||
$subtype_map = $this->newEditEngineSubtypeMap();
|
||||
return idx($subtype_map, $subtype_key);
|
||||
}
|
||||
|
||||
/* -( PhabricatorFulltextInterface )--------------------------------------- */
|
||||
|
||||
|
|
|
@ -211,4 +211,14 @@ final class ManiphestTransaction
|
|||
return parent::getNoEffectDescription();
|
||||
}
|
||||
|
||||
public function renderSubtypeName($value) {
|
||||
$object = $this->getObject();
|
||||
$map = $object->newEditEngineSubtypeMap();
|
||||
if (!isset($map[$value])) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
return $map[$value]->getName();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ final class ManiphestTaskSubtypeDatasource
|
|||
|
||||
$result = id(new PhabricatorTypeaheadResult())
|
||||
->setIcon($subtype->getIcon())
|
||||
->setColor($subtype->getColor())
|
||||
->setPHID($key)
|
||||
->setName($subtype->getName());
|
||||
|
||||
|
|
|
@ -56,6 +56,9 @@ final class ManiphestTaskListView extends ManiphestView {
|
|||
Javelin::initBehavior('maniphest-list-editor');
|
||||
}
|
||||
|
||||
$subtype_map = id(new ManiphestTask())
|
||||
->newEditEngineSubtypeMap();
|
||||
|
||||
foreach ($this->tasks as $task) {
|
||||
$item = id(new PHUIObjectItemView())
|
||||
->setUser($this->getUser())
|
||||
|
@ -94,6 +97,13 @@ final class ManiphestTaskListView extends ManiphestView {
|
|||
$item->addSigil('maniphest-task');
|
||||
}
|
||||
|
||||
$subtype = $task->newSubtypeObject();
|
||||
if ($subtype && $subtype->hasTagView()) {
|
||||
$subtype_tag = $subtype->newTagView()
|
||||
->setSlimShady(true);
|
||||
$item->addAttribute($subtype_tag);
|
||||
}
|
||||
|
||||
$project_handles = array_select_keys(
|
||||
$handles,
|
||||
array_reverse($task->getProjectPHIDs()));
|
||||
|
|
|
@ -50,6 +50,32 @@ final class ManiphestTaskPointsTransaction
|
|||
}
|
||||
}
|
||||
|
||||
public function getTitleForFeed() {
|
||||
$old = $this->getOldValue();
|
||||
$new = $this->getNewValue();
|
||||
|
||||
if ($old === null) {
|
||||
return pht(
|
||||
'%s set the point value for %s to %s.',
|
||||
$this->renderAuthor(),
|
||||
$this->renderObject(),
|
||||
$this->renderNewValue());
|
||||
} else if ($new === null) {
|
||||
return pht(
|
||||
'%s removed the point value for %s.',
|
||||
$this->renderAuthor(),
|
||||
$this->renderObject());
|
||||
} else {
|
||||
return pht(
|
||||
'%s changed the point value for %s from %s to %s.',
|
||||
$this->renderAuthor(),
|
||||
$this->renderObject(),
|
||||
$this->renderOldValue(),
|
||||
$this->renderNewValue());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function validateTransactions($object, array $xactions) {
|
||||
$errors = array();
|
||||
|
||||
|
|
|
@ -19,8 +19,8 @@ final class ManiphestTaskTitleTransaction
|
|||
|
||||
public function getActionName() {
|
||||
$old = $this->getOldValue();
|
||||
$new = $this->getNewValue();
|
||||
if ($old === null) {
|
||||
|
||||
if (!strlen($old)) {
|
||||
return pht('Created');
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,8 @@ final class ManiphestTaskTitleTransaction
|
|||
|
||||
public function getTitle() {
|
||||
$old = $this->getOldValue();
|
||||
if ($old === null) {
|
||||
|
||||
if (!strlen($old)) {
|
||||
return pht(
|
||||
'%s created this task.',
|
||||
$this->renderAuthor());
|
||||
|
|
|
@ -3,14 +3,4 @@
|
|||
abstract class ManiphestTaskTransactionType
|
||||
extends PhabricatorModularTransactionType {
|
||||
|
||||
public function renderSubtypeName($value) {
|
||||
$object = $this->getObject();
|
||||
$map = $object->newEditEngineSubtypeMap();
|
||||
if (!isset($map[$value])) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
return $map[$value]->getName();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -218,20 +218,39 @@ final class PhabricatorAppSearchEngine
|
|||
|
||||
$configure = id(new PHUIButtonView())
|
||||
->setTag('a')
|
||||
->setIcon('fa-gears')
|
||||
->setHref('/applications/view/'.get_class($application).'/')
|
||||
->setText(pht('Configure'))
|
||||
->setColor(PHUIButtonView::GREY);
|
||||
|
||||
$name = $application->getName();
|
||||
if ($application->isPrototype()) {
|
||||
$name = $name.' '.pht('(Prototype)');
|
||||
}
|
||||
|
||||
$item = id(new PHUIObjectItemView())
|
||||
->setHeader($name)
|
||||
->setImageIcon($icon)
|
||||
->setSubhead($description)
|
||||
->setLaunchButton($configure);
|
||||
->setSideColumn($configure);
|
||||
|
||||
if (!$application->isFirstParty()) {
|
||||
$tag = id(new PHUITagView())
|
||||
->setName(pht('Extension'))
|
||||
->setIcon('fa-puzzle-piece')
|
||||
->setColor(PHUITagView::COLOR_BLUE)
|
||||
->setType(PHUITagView::TYPE_SHADE)
|
||||
->setSlimShady(true);
|
||||
$item->addAttribute($tag);
|
||||
}
|
||||
|
||||
if ($application->isPrototype()) {
|
||||
$prototype_tag = id(new PHUITagView())
|
||||
->setName(pht('Prototype'))
|
||||
->setIcon('fa-exclamation-circle')
|
||||
->setColor(PHUITagView::COLOR_ORANGE)
|
||||
->setType(PHUITagView::TYPE_SHADE)
|
||||
->setSlimShady(true);
|
||||
$item->addAttribute($prototype_tag);
|
||||
}
|
||||
|
||||
$item->addAttribute($description);
|
||||
|
||||
if ($application->getBaseURI() && $application->isInstalled()) {
|
||||
$item->setHref($application->getBaseURI());
|
||||
|
@ -242,10 +261,6 @@ final class PhabricatorAppSearchEngine
|
|||
$item->setDisabled(true);
|
||||
}
|
||||
|
||||
if (!$application->isFirstParty()) {
|
||||
$item->addAttribute(pht('Extension'));
|
||||
}
|
||||
|
||||
$list->addItem($item);
|
||||
}
|
||||
|
||||
|
|
|
@ -51,6 +51,9 @@ final class PhabricatorNuanceApplication extends PhabricatorApplication {
|
|||
$this->getQueryRoutePattern() => 'NuanceQueueListController',
|
||||
$this->getEditRoutePattern('edit/') => 'NuanceQueueEditController',
|
||||
'view/(?P<id>[1-9]\d*)/' => 'NuanceQueueViewController',
|
||||
'work/(?P<id>[1-9]\d*)/' => 'NuanceQueueWorkController',
|
||||
'action/(?P<queueID>[1-9]\d*)/(?P<action>[^/]+)/(?P<id>[1-9]\d*)/'
|
||||
=> 'NuanceItemActionController',
|
||||
),
|
||||
),
|
||||
'/action/' => array(
|
||||
|
|
113
src/applications/nuance/command/NuanceCommandImplementation.php
Normal file
113
src/applications/nuance/command/NuanceCommandImplementation.php
Normal file
|
@ -0,0 +1,113 @@
|
|||
<?php
|
||||
|
||||
abstract class NuanceCommandImplementation
|
||||
extends Phobject {
|
||||
|
||||
private $actor;
|
||||
|
||||
private $transactionQueue = array();
|
||||
|
||||
final public function setActor(PhabricatorUser $actor) {
|
||||
$this->actor = $actor;
|
||||
return $this;
|
||||
}
|
||||
|
||||
final public function getActor() {
|
||||
return $this->actor;
|
||||
}
|
||||
|
||||
abstract public function getCommandName();
|
||||
abstract public function canApplyToItem(NuanceItem $item);
|
||||
|
||||
public function canApplyImmediately(
|
||||
NuanceItem $item,
|
||||
NuanceItemCommand $command) {
|
||||
return false;
|
||||
}
|
||||
|
||||
abstract protected function executeCommand(
|
||||
NuanceItem $item,
|
||||
NuanceItemCommand $command);
|
||||
|
||||
final public function applyCommand(
|
||||
NuanceItem $item,
|
||||
NuanceItemCommand $command) {
|
||||
|
||||
$command_key = $command->getCommand();
|
||||
$implementation_key = $this->getCommandKey();
|
||||
if ($command_key !== $implementation_key) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'This command implementation("%s") can not apply a command of a '.
|
||||
'different type ("%s").',
|
||||
$implementation_key,
|
||||
$command_key));
|
||||
}
|
||||
|
||||
if (!$this->canApplyToItem($item)) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'This command implementation ("%s") can not be applied to an '.
|
||||
'item of type "%s".',
|
||||
$implementation_key,
|
||||
$item->getItemType()));
|
||||
}
|
||||
|
||||
$this->transactionQueue = array();
|
||||
|
||||
$command_type = NuanceItemCommandTransaction::TRANSACTIONTYPE;
|
||||
$command_xaction = $this->newTransaction($command_type);
|
||||
|
||||
$result = $this->executeCommand($item, $command);
|
||||
|
||||
$xactions = $this->transactionQueue;
|
||||
$this->transactionQueue = array();
|
||||
|
||||
$command_xaction->setNewValue(
|
||||
array(
|
||||
'command' => $command->getCommand(),
|
||||
'parameters' => $command->getParameters(),
|
||||
'result' => $result,
|
||||
));
|
||||
|
||||
// TODO: Maybe preserve the actor's original content source?
|
||||
$source = PhabricatorContentSource::newForSource(
|
||||
PhabricatorDaemonContentSource::SOURCECONST);
|
||||
|
||||
$actor = $this->getActor();
|
||||
|
||||
id(new NuanceItemEditor())
|
||||
->setActor($actor)
|
||||
->setActingAsPHID($command->getAuthorPHID())
|
||||
->setContentSource($source)
|
||||
->setContinueOnMissingFields(true)
|
||||
->setContinueOnNoEffect(true)
|
||||
->applyTransactions($item, $xactions);
|
||||
}
|
||||
|
||||
final public function getCommandKey() {
|
||||
return $this->getPhobjectClassConstant('COMMANDKEY');
|
||||
}
|
||||
|
||||
final public static function getAllCommands() {
|
||||
return id(new PhutilClassMapQuery())
|
||||
->setAncestorClass(__CLASS__)
|
||||
->setUniqueMethod('getCommandKey')
|
||||
->execute();
|
||||
}
|
||||
|
||||
protected function newTransaction($type) {
|
||||
$xaction = id(new NuanceItemTransaction())
|
||||
->setTransactionType($type);
|
||||
|
||||
$this->transactionQueue[] = $xaction;
|
||||
|
||||
return $xaction;
|
||||
}
|
||||
|
||||
protected function newStatusTransaction($status) {
|
||||
return $this->newTransaction(NuanceItemStatusTransaction::TRANSACTIONTYPE)
|
||||
->setNewValue($status);
|
||||
}
|
||||
|
||||
}
|
37
src/applications/nuance/command/NuanceItemCommandSpec.php
Normal file
37
src/applications/nuance/command/NuanceItemCommandSpec.php
Normal file
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
final class NuanceItemCommandSpec
|
||||
extends Phobject {
|
||||
|
||||
private $commandKey;
|
||||
private $name;
|
||||
private $icon;
|
||||
|
||||
public function setCommandKey($command_key) {
|
||||
$this->commandKey = $command_key;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCommandKey() {
|
||||
return $this->commandKey;
|
||||
}
|
||||
|
||||
public function setName($name) {
|
||||
$this->name = $name;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getName() {
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function setIcon($icon) {
|
||||
$this->icon = $icon;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getIcon() {
|
||||
return $this->icon;
|
||||
}
|
||||
|
||||
}
|
29
src/applications/nuance/command/NuanceTrashCommand.php
Normal file
29
src/applications/nuance/command/NuanceTrashCommand.php
Normal file
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
final class NuanceTrashCommand
|
||||
extends NuanceCommandImplementation {
|
||||
|
||||
const COMMANDKEY = 'trash';
|
||||
|
||||
public function getCommandName() {
|
||||
return pht('Throw in Trash');
|
||||
}
|
||||
|
||||
public function canApplyToItem(NuanceItem $item) {
|
||||
$type = $item->getImplementation();
|
||||
return ($type instanceof NuanceFormItemType);
|
||||
}
|
||||
|
||||
public function canApplyImmediately(
|
||||
NuanceItem $item,
|
||||
NuanceItemCommand $command) {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function executeCommand(
|
||||
NuanceItem $item,
|
||||
NuanceItemCommand $command) {
|
||||
$this->newStatusTransaction(NuanceItem::STATUS_CLOSED);
|
||||
}
|
||||
|
||||
}
|
|
@ -6,6 +6,14 @@ final class NuanceItemActionController extends NuanceController {
|
|||
$viewer = $this->getViewer();
|
||||
$id = $request->getURIData('id');
|
||||
|
||||
if (!$request->validateCSRF()) {
|
||||
return new Aphront400Response();
|
||||
}
|
||||
|
||||
// NOTE: This controller can be reached from an individual item (usually
|
||||
// by a user) or while working through a queue (usually by staff). When
|
||||
// a command originates from a queue, the URI will have a queue ID.
|
||||
|
||||
$item = id(new NuanceItemQuery())
|
||||
->setViewer($viewer)
|
||||
->withIDs(array($id))
|
||||
|
@ -14,13 +22,100 @@ final class NuanceItemActionController extends NuanceController {
|
|||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$cancel_uri = $item->getURI();
|
||||
|
||||
$queue_id = $request->getURIData('queueID');
|
||||
$queue = null;
|
||||
if ($queue_id) {
|
||||
$queue = id(new NuanceQueueQuery())
|
||||
->setViewer($viewer)
|
||||
->withIDs(array($queue_id))
|
||||
->executeOne();
|
||||
if (!$queue) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$item_queue = $item->getQueue();
|
||||
if (!$item_queue || ($item_queue->getPHID() != $queue->getPHID())) {
|
||||
return $this->newDialog()
|
||||
->setTitle(pht('Wrong Queue'))
|
||||
->appendParagraph(
|
||||
pht(
|
||||
'You are trying to act on this item from the wrong queue: it '.
|
||||
'is currently in a different queue.'))
|
||||
->addCancelButton($cancel_uri);
|
||||
}
|
||||
}
|
||||
|
||||
$action = $request->getURIData('action');
|
||||
|
||||
$impl = $item->getImplementation();
|
||||
$impl->setViewer($viewer);
|
||||
$impl->setController($this);
|
||||
|
||||
return $impl->buildActionResponse($item, $action);
|
||||
$executors = NuanceCommandImplementation::getAllCommands();
|
||||
$executor = idx($executors, $action);
|
||||
if (!$executor) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$executor = id(clone $executor)
|
||||
->setActor($viewer);
|
||||
|
||||
if (!$executor->canApplyToItem($item)) {
|
||||
return $this->newDialog()
|
||||
->setTitle(pht('Command Not Supported'))
|
||||
->appendParagraph(
|
||||
pht(
|
||||
'This item does not support the specified command ("%s").',
|
||||
$action))
|
||||
->addCancelButton($cancel_uri);
|
||||
}
|
||||
|
||||
$command = NuanceItemCommand::initializeNewCommand()
|
||||
->setItemPHID($item->getPHID())
|
||||
->setAuthorPHID($viewer->getPHID())
|
||||
->setCommand($action);
|
||||
|
||||
if ($queue) {
|
||||
$command->setQueuePHID($queue->getPHID());
|
||||
}
|
||||
|
||||
$command->save();
|
||||
|
||||
// If this command can be applied immediately, try to apply it now.
|
||||
|
||||
// In most cases, local commands (like closing an item) can be applied
|
||||
// immediately.
|
||||
|
||||
// Commands that require making a call to a remote system (for example,
|
||||
// to reply to a tweet or close a remote object) are usually done in the
|
||||
// background so the user doesn't have to wait for the operation to
|
||||
// complete before they can continue work.
|
||||
|
||||
$did_apply = false;
|
||||
$immediate = $executor->canApplyImmediately($item, $command);
|
||||
if ($immediate) {
|
||||
// TODO: Move this stuff to a new Engine, and have the controller and
|
||||
// worker both call into the Engine.
|
||||
$worker = new NuanceItemUpdateWorker(array());
|
||||
$did_apply = $worker->executeCommands($item, array($command));
|
||||
}
|
||||
|
||||
// If this can't be applied immediately or we were unable to get a lock
|
||||
// fast enough, do the update in the background instead.
|
||||
if (!$did_apply) {
|
||||
$item->scheduleUpdate();
|
||||
}
|
||||
|
||||
if ($queue) {
|
||||
$done_uri = $queue->getWorkURI();
|
||||
} else {
|
||||
$done_uri = $item->getURI();
|
||||
}
|
||||
|
||||
return id(new AphrontRedirectResponse())
|
||||
->setURI($done_uri);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -26,14 +26,12 @@ final class NuanceItemViewController extends NuanceController {
|
|||
|
||||
$curtain = $this->buildCurtain($item);
|
||||
$content = $this->buildContent($item);
|
||||
$commands = $this->buildCommands($item);
|
||||
|
||||
$timeline = $this->buildTransactionTimeline(
|
||||
$item,
|
||||
new NuanceItemTransactionQuery());
|
||||
|
||||
$main = array(
|
||||
$commands,
|
||||
$content,
|
||||
$timeline,
|
||||
);
|
||||
|
@ -91,36 +89,4 @@ final class NuanceItemViewController extends NuanceController {
|
|||
return $impl->buildItemView($item);
|
||||
}
|
||||
|
||||
private function buildCommands(NuanceItem $item) {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$commands = id(new NuanceItemCommandQuery())
|
||||
->setViewer($viewer)
|
||||
->withItemPHIDs(array($item->getPHID()))
|
||||
->execute();
|
||||
$commands = msort($commands, 'getID');
|
||||
|
||||
if (!$commands) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$rows = array();
|
||||
foreach ($commands as $command) {
|
||||
$rows[] = array(
|
||||
$command->getCommand(),
|
||||
);
|
||||
}
|
||||
|
||||
$table = id(new AphrontTableView($rows))
|
||||
->setHeaders(
|
||||
array(
|
||||
pht('Command'),
|
||||
));
|
||||
|
||||
return id(new PHUIObjectBoxView())
|
||||
->setHeaderText(pht('Pending Commands'))
|
||||
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
||||
->setTable($table);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -70,6 +70,14 @@ final class NuanceQueueViewController
|
|||
->setDisabled(!$can_edit)
|
||||
->setWorkflow(!$can_edit));
|
||||
|
||||
$curtain->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setName(pht('Begin Work'))
|
||||
->setIcon('fa-play-circle-o')
|
||||
->setHref($this->getApplicationURI("queue/work/{$id}/"))
|
||||
->setDisabled(!$can_edit)
|
||||
->setWorkflow(!$can_edit));
|
||||
|
||||
return $curtain;
|
||||
}
|
||||
|
||||
|
|
186
src/applications/nuance/controller/NuanceQueueWorkController.php
Normal file
186
src/applications/nuance/controller/NuanceQueueWorkController.php
Normal file
|
@ -0,0 +1,186 @@
|
|||
<?php
|
||||
|
||||
final class NuanceQueueWorkController
|
||||
extends NuanceQueueController {
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$queue = id(new NuanceQueueQuery())
|
||||
->setViewer($viewer)
|
||||
->withIDs(array($request->getURIData('id')))
|
||||
->executeOne();
|
||||
if (!$queue) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$title = $queue->getName();
|
||||
|
||||
$crumbs = $this->buildApplicationCrumbs();
|
||||
$crumbs->addTextCrumb(pht('Queues'), $this->getApplicationURI('queue/'));
|
||||
$crumbs->addTextCrumb($queue->getName(), $queue->getURI());
|
||||
$crumbs->addTextCrumb(pht('Work'));
|
||||
$crumbs->setBorder(true);
|
||||
|
||||
// For now, just pick the first open item.
|
||||
|
||||
$items = id(new NuanceItemQuery())
|
||||
->setViewer($viewer)
|
||||
->withQueuePHIDs(
|
||||
array(
|
||||
$queue->getPHID(),
|
||||
))
|
||||
->withStatuses(
|
||||
array(
|
||||
NuanceItem::STATUS_OPEN,
|
||||
))
|
||||
->requireCapabilities(
|
||||
array(
|
||||
PhabricatorPolicyCapability::CAN_VIEW,
|
||||
PhabricatorPolicyCapability::CAN_EDIT,
|
||||
))
|
||||
->setLimit(5)
|
||||
->execute();
|
||||
|
||||
if (!$items) {
|
||||
return $this->newDialog()
|
||||
->setTitle(pht('Queue Empty'))
|
||||
->appendParagraph(
|
||||
pht(
|
||||
'This queue has no open items which you have permission to '.
|
||||
'work on.'))
|
||||
->addCancelButton($queue->getURI());
|
||||
}
|
||||
|
||||
$item = head($items);
|
||||
|
||||
$curtain = $this->buildCurtain($queue, $item);
|
||||
|
||||
$timeline = $this->buildTransactionTimeline(
|
||||
$item,
|
||||
new NuanceItemTransactionQuery());
|
||||
$timeline->setShouldTerminate(true);
|
||||
|
||||
$impl = $item->getImplementation()
|
||||
->setViewer($viewer);
|
||||
|
||||
$commands = $this->buildCommands($item);
|
||||
$work_content = $impl->buildItemWorkView($item);
|
||||
|
||||
$view = id(new PHUITwoColumnView())
|
||||
->setCurtain($curtain)
|
||||
->setMainColumn(
|
||||
array(
|
||||
$commands,
|
||||
$work_content,
|
||||
$timeline,
|
||||
));
|
||||
|
||||
return $this->newPage()
|
||||
->setTitle($title)
|
||||
->setCrumbs($crumbs)
|
||||
->appendChild($view);
|
||||
}
|
||||
|
||||
private function buildCurtain(NuanceQueue $queue, NuanceItem $item) {
|
||||
$viewer = $this->getViewer();
|
||||
$id = $queue->getID();
|
||||
|
||||
$curtain = $this->newCurtainView();
|
||||
|
||||
$impl = $item->getImplementation();
|
||||
$commands = $impl->buildWorkCommands($item);
|
||||
|
||||
foreach ($commands as $command) {
|
||||
$command_key = $command->getCommandKey();
|
||||
|
||||
$item_id = $item->getID();
|
||||
|
||||
$action_uri = "queue/action/{$id}/{$command_key}/{$item_id}/";
|
||||
$action_uri = $this->getApplicationURI($action_uri);
|
||||
|
||||
$curtain->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setName($command->getName())
|
||||
->setIcon($command->getIcon())
|
||||
->setHref($action_uri)
|
||||
->setWorkflow(true));
|
||||
}
|
||||
|
||||
$curtain->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setType(PhabricatorActionView::TYPE_DIVIDER));
|
||||
|
||||
$curtain->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setType(PhabricatorActionView::TYPE_LABEL)
|
||||
->setName(pht('Queue Actions')));
|
||||
|
||||
$curtain->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setName(pht('Manage Queue'))
|
||||
->setIcon('fa-cog')
|
||||
->setHref($this->getApplicationURI("queue/view/{$id}/")));
|
||||
|
||||
return $curtain;
|
||||
}
|
||||
|
||||
private function buildCommands(NuanceItem $item) {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$commands = id(new NuanceItemCommandQuery())
|
||||
->setViewer($viewer)
|
||||
->withItemPHIDs(array($item->getPHID()))
|
||||
->withStatuses(
|
||||
array(
|
||||
NuanceItemCommand::STATUS_ISSUED,
|
||||
NuanceItemCommand::STATUS_EXECUTING,
|
||||
NuanceItemCommand::STATUS_FAILED,
|
||||
))
|
||||
->execute();
|
||||
$commands = msort($commands, 'getID');
|
||||
|
||||
if (!$commands) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$rows = array();
|
||||
foreach ($commands as $command) {
|
||||
$icon = $command->getStatusIcon();
|
||||
$color = $command->getStatusColor();
|
||||
|
||||
$rows[] = array(
|
||||
$command->getID(),
|
||||
id(new PHUIIconView())
|
||||
->setIcon($icon, $color),
|
||||
$viewer->renderHandle($command->getAuthorPHID()),
|
||||
$command->getCommand(),
|
||||
phabricator_datetime($command->getDateCreated(), $viewer),
|
||||
);
|
||||
}
|
||||
|
||||
$table = id(new AphrontTableView($rows))
|
||||
->setHeaders(
|
||||
array(
|
||||
pht('ID'),
|
||||
null,
|
||||
pht('Actor'),
|
||||
pht('Command'),
|
||||
pht('Date'),
|
||||
))
|
||||
->setColumnClasses(
|
||||
array(
|
||||
null,
|
||||
'icon',
|
||||
null,
|
||||
'pri',
|
||||
'wide right',
|
||||
));
|
||||
|
||||
return id(new PHUIObjectBoxView())
|
||||
->setHeaderText(pht('Pending Commands'))
|
||||
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
||||
->setTable($table);
|
||||
}
|
||||
|
||||
}
|
|
@ -17,10 +17,9 @@ final class NuanceGitHubIssuesImportCursor
|
|||
|
||||
$container_key = null;
|
||||
|
||||
return NuanceItem::initializeNewItem()
|
||||
return NuanceItem::initializeNewItem(NuanceGitHubEventItemType::ITEMTYPE)
|
||||
->setStatus(NuanceItem::STATUS_IMPORTING)
|
||||
->setSourcePHID($source->getPHID())
|
||||
->setItemType(NuanceGitHubEventItemType::ITEMTYPE)
|
||||
->setItemKey($item_key)
|
||||
->setItemContainerKey($container_key)
|
||||
->setItemProperty('api.type', 'issue')
|
||||
|
|
|
@ -36,10 +36,9 @@ final class NuanceGitHubRepositoryImportCursor
|
|||
$container_key = "github.issue.{$issue_id}";
|
||||
}
|
||||
|
||||
return NuanceItem::initializeNewItem()
|
||||
return NuanceItem::initializeNewItem(NuanceGitHubEventItemType::ITEMTYPE)
|
||||
->setStatus(NuanceItem::STATUS_IMPORTING)
|
||||
->setSourcePHID($source->getPHID())
|
||||
->setItemType(NuanceGitHubEventItemType::ITEMTYPE)
|
||||
->setItemKey($item_key)
|
||||
->setItemContainerKey($container_key)
|
||||
->setItemProperty('api.type', 'repository')
|
||||
|
|
|
@ -14,104 +14,10 @@ final class NuanceItemEditor
|
|||
public function getTransactionTypes() {
|
||||
$types = parent::getTransactionTypes();
|
||||
|
||||
$types[] = NuanceItemTransaction::TYPE_OWNER;
|
||||
$types[] = NuanceItemTransaction::TYPE_SOURCE;
|
||||
$types[] = NuanceItemTransaction::TYPE_REQUESTOR;
|
||||
$types[] = NuanceItemTransaction::TYPE_PROPERTY;
|
||||
$types[] = NuanceItemTransaction::TYPE_QUEUE;
|
||||
$types[] = NuanceItemTransaction::TYPE_COMMAND;
|
||||
|
||||
$types[] = PhabricatorTransactions::TYPE_EDGE;
|
||||
$types[] = PhabricatorTransactions::TYPE_COMMENT;
|
||||
$types[] = PhabricatorTransactions::TYPE_VIEW_POLICY;
|
||||
$types[] = PhabricatorTransactions::TYPE_EDIT_POLICY;
|
||||
|
||||
return $types;
|
||||
}
|
||||
|
||||
protected function getCustomTransactionOldValue(
|
||||
PhabricatorLiskDAO $object,
|
||||
PhabricatorApplicationTransaction $xaction) {
|
||||
|
||||
switch ($xaction->getTransactionType()) {
|
||||
case NuanceItemTransaction::TYPE_REQUESTOR:
|
||||
return $object->getRequestorPHID();
|
||||
case NuanceItemTransaction::TYPE_SOURCE:
|
||||
return $object->getSourcePHID();
|
||||
case NuanceItemTransaction::TYPE_OWNER:
|
||||
return $object->getOwnerPHID();
|
||||
case NuanceItemTransaction::TYPE_QUEUE:
|
||||
return $object->getQueuePHID();
|
||||
case NuanceItemTransaction::TYPE_PROPERTY:
|
||||
$key = $xaction->getMetadataValue(
|
||||
NuanceItemTransaction::PROPERTY_KEY);
|
||||
return $object->getNuanceProperty($key);
|
||||
case NuanceItemTransaction::TYPE_COMMAND:
|
||||
return null;
|
||||
}
|
||||
|
||||
return parent::getCustomTransactionOldValue($object, $xaction);
|
||||
}
|
||||
|
||||
protected function getCustomTransactionNewValue(
|
||||
PhabricatorLiskDAO $object,
|
||||
PhabricatorApplicationTransaction $xaction) {
|
||||
|
||||
switch ($xaction->getTransactionType()) {
|
||||
case NuanceItemTransaction::TYPE_REQUESTOR:
|
||||
case NuanceItemTransaction::TYPE_SOURCE:
|
||||
case NuanceItemTransaction::TYPE_OWNER:
|
||||
case NuanceItemTransaction::TYPE_PROPERTY:
|
||||
case NuanceItemTransaction::TYPE_QUEUE:
|
||||
case NuanceItemTransaction::TYPE_COMMAND:
|
||||
return $xaction->getNewValue();
|
||||
}
|
||||
|
||||
return parent::getCustomTransactionNewValue($object, $xaction);
|
||||
}
|
||||
|
||||
protected function applyCustomInternalTransaction(
|
||||
PhabricatorLiskDAO $object,
|
||||
PhabricatorApplicationTransaction $xaction) {
|
||||
|
||||
switch ($xaction->getTransactionType()) {
|
||||
case NuanceItemTransaction::TYPE_REQUESTOR:
|
||||
$object->setRequestorPHID($xaction->getNewValue());
|
||||
break;
|
||||
case NuanceItemTransaction::TYPE_SOURCE:
|
||||
$object->setSourcePHID($xaction->getNewValue());
|
||||
break;
|
||||
case NuanceItemTransaction::TYPE_OWNER:
|
||||
$object->setOwnerPHID($xaction->getNewValue());
|
||||
break;
|
||||
case NuanceItemTransaction::TYPE_QUEUE:
|
||||
$object->setQueuePHID($xaction->getNewValue());
|
||||
break;
|
||||
case NuanceItemTransaction::TYPE_PROPERTY:
|
||||
$key = $xaction->getMetadataValue(
|
||||
NuanceItemTransaction::PROPERTY_KEY);
|
||||
$object->setNuanceProperty($key, $xaction->getNewValue());
|
||||
break;
|
||||
case NuanceItemTransaction::TYPE_COMMAND:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected function applyCustomExternalTransaction(
|
||||
PhabricatorLiskDAO $object,
|
||||
PhabricatorApplicationTransaction $xaction) {
|
||||
|
||||
switch ($xaction->getTransactionType()) {
|
||||
case NuanceItemTransaction::TYPE_REQUESTOR:
|
||||
case NuanceItemTransaction::TYPE_SOURCE:
|
||||
case NuanceItemTransaction::TYPE_OWNER:
|
||||
case NuanceItemTransaction::TYPE_PROPERTY:
|
||||
case NuanceItemTransaction::TYPE_QUEUE:
|
||||
case NuanceItemTransaction::TYPE_COMMAND:
|
||||
return;
|
||||
}
|
||||
|
||||
return parent::applyCustomExternalTransaction($object, $xaction);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -75,7 +75,7 @@ final class NuanceQueueEditEngine
|
|||
->setKey('name')
|
||||
->setLabel(pht('Name'))
|
||||
->setDescription(pht('Name of the queue.'))
|
||||
->setTransactionType(NuanceQueueTransaction::TYPE_NAME)
|
||||
->setTransactionType(NuanceQueueNameTransaction::TRANSACTIONTYPE)
|
||||
->setIsRequired(true)
|
||||
->setValue($object->getName()),
|
||||
);
|
||||
|
|
|
@ -14,89 +14,10 @@ final class NuanceQueueEditor
|
|||
public function getTransactionTypes() {
|
||||
$types = parent::getTransactionTypes();
|
||||
|
||||
$types[] = NuanceQueueTransaction::TYPE_NAME;
|
||||
|
||||
$types[] = PhabricatorTransactions::TYPE_VIEW_POLICY;
|
||||
$types[] = PhabricatorTransactions::TYPE_EDIT_POLICY;
|
||||
|
||||
return $types;
|
||||
}
|
||||
|
||||
protected function getCustomTransactionOldValue(
|
||||
PhabricatorLiskDAO $object,
|
||||
PhabricatorApplicationTransaction $xaction) {
|
||||
|
||||
switch ($xaction->getTransactionType()) {
|
||||
case NuanceQueueTransaction::TYPE_NAME:
|
||||
return $object->getName();
|
||||
}
|
||||
|
||||
return parent::getCustomTransactionOldValue($object, $xaction);
|
||||
}
|
||||
|
||||
protected function getCustomTransactionNewValue(
|
||||
PhabricatorLiskDAO $object,
|
||||
PhabricatorApplicationTransaction $xaction) {
|
||||
|
||||
switch ($xaction->getTransactionType()) {
|
||||
case NuanceQueueTransaction::TYPE_NAME:
|
||||
return $xaction->getNewValue();
|
||||
}
|
||||
|
||||
return parent::getCustomTransactionNewValue($object, $xaction);
|
||||
}
|
||||
|
||||
protected function applyCustomInternalTransaction(
|
||||
PhabricatorLiskDAO $object,
|
||||
PhabricatorApplicationTransaction $xaction) {
|
||||
|
||||
switch ($xaction->getTransactionType()) {
|
||||
case NuanceQueueTransaction::TYPE_NAME:
|
||||
$object->setName($xaction->getNewValue());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected function applyCustomExternalTransaction(
|
||||
PhabricatorLiskDAO $object,
|
||||
PhabricatorApplicationTransaction $xaction) {
|
||||
|
||||
switch ($xaction->getTransactionType()) {
|
||||
case NuanceQueueTransaction::TYPE_NAME:
|
||||
return;
|
||||
}
|
||||
|
||||
return parent::applyCustomExternalTransaction($object, $xaction);
|
||||
}
|
||||
|
||||
protected function validateTransaction(
|
||||
PhabricatorLiskDAO $object,
|
||||
$type,
|
||||
array $xactions) {
|
||||
|
||||
$errors = parent::validateTransaction($object, $type, $xactions);
|
||||
|
||||
switch ($type) {
|
||||
case NuanceQueueTransaction::TYPE_NAME:
|
||||
$missing = $this->validateIsEmptyTextField(
|
||||
$object->getName(),
|
||||
$xactions);
|
||||
|
||||
if ($missing) {
|
||||
$error = new PhabricatorApplicationTransactionValidationError(
|
||||
$type,
|
||||
pht('Required'),
|
||||
pht('A queue must have a name.'),
|
||||
nonempty(last($xactions), null));
|
||||
|
||||
$error->setIsMissingFieldError(true);
|
||||
$errors[] = $error;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return $errors;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -96,14 +96,15 @@ final class NuanceSourceEditEngine
|
|||
->setKey('name')
|
||||
->setLabel(pht('Name'))
|
||||
->setDescription(pht('Name of the source.'))
|
||||
->setTransactionType(NuanceSourceTransaction::TYPE_NAME)
|
||||
->setTransactionType(NuanceSourceNameTransaction::TRANSACTIONTYPE)
|
||||
->setIsRequired(true)
|
||||
->setValue($object->getName()),
|
||||
id(new PhabricatorDatasourceEditField())
|
||||
->setKey('defaultQueue')
|
||||
->setLabel(pht('Default Queue'))
|
||||
->setDescription(pht('Default queue.'))
|
||||
->setTransactionType(NuanceSourceTransaction::TYPE_DEFAULT_QUEUE)
|
||||
->setTransactionType(
|
||||
NuanceSourceDefaultQueueTransaction::TRANSACTIONTYPE)
|
||||
->setDatasource(new NuanceQueueDatasource())
|
||||
->setSingleValue($object->getDefaultQueuePHID()),
|
||||
);
|
||||
|
|
|
@ -18,111 +18,10 @@ final class NuanceSourceEditor
|
|||
public function getTransactionTypes() {
|
||||
$types = parent::getTransactionTypes();
|
||||
|
||||
$types[] = NuanceSourceTransaction::TYPE_NAME;
|
||||
$types[] = NuanceSourceTransaction::TYPE_DEFAULT_QUEUE;
|
||||
|
||||
$types[] = PhabricatorTransactions::TYPE_EDGE;
|
||||
$types[] = PhabricatorTransactions::TYPE_COMMENT;
|
||||
$types[] = PhabricatorTransactions::TYPE_VIEW_POLICY;
|
||||
$types[] = PhabricatorTransactions::TYPE_EDIT_POLICY;
|
||||
|
||||
return $types;
|
||||
}
|
||||
|
||||
protected function getCustomTransactionOldValue(
|
||||
PhabricatorLiskDAO $object,
|
||||
PhabricatorApplicationTransaction $xaction) {
|
||||
|
||||
switch ($xaction->getTransactionType()) {
|
||||
case NuanceSourceTransaction::TYPE_NAME:
|
||||
return $object->getName();
|
||||
case NuanceSourceTransaction::TYPE_DEFAULT_QUEUE:
|
||||
return $object->getDefaultQueuePHID();
|
||||
}
|
||||
|
||||
return parent::getCustomTransactionOldValue($object, $xaction);
|
||||
}
|
||||
|
||||
protected function getCustomTransactionNewValue(
|
||||
PhabricatorLiskDAO $object,
|
||||
PhabricatorApplicationTransaction $xaction) {
|
||||
|
||||
switch ($xaction->getTransactionType()) {
|
||||
case NuanceSourceTransaction::TYPE_NAME:
|
||||
case NuanceSourceTransaction::TYPE_DEFAULT_QUEUE:
|
||||
return $xaction->getNewValue();
|
||||
}
|
||||
|
||||
return parent::getCustomTransactionNewValue($object, $xaction);
|
||||
}
|
||||
|
||||
protected function applyCustomInternalTransaction(
|
||||
PhabricatorLiskDAO $object,
|
||||
PhabricatorApplicationTransaction $xaction) {
|
||||
|
||||
switch ($xaction->getTransactionType()) {
|
||||
case NuanceSourceTransaction::TYPE_NAME:
|
||||
$object->setName($xaction->getNewValue());
|
||||
break;
|
||||
case NuanceSourceTransaction::TYPE_DEFAULT_QUEUE:
|
||||
$object->setDefaultQueuePHID($xaction->getNewValue());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected function applyCustomExternalTransaction(
|
||||
PhabricatorLiskDAO $object,
|
||||
PhabricatorApplicationTransaction $xaction) {
|
||||
|
||||
switch ($xaction->getTransactionType()) {
|
||||
case NuanceSourceTransaction::TYPE_NAME:
|
||||
case NuanceSourceTransaction::TYPE_DEFAULT_QUEUE:
|
||||
return;
|
||||
}
|
||||
|
||||
return parent::applyCustomExternalTransaction($object, $xaction);
|
||||
}
|
||||
|
||||
protected function validateTransaction(
|
||||
PhabricatorLiskDAO $object,
|
||||
$type,
|
||||
array $xactions) {
|
||||
|
||||
$errors = parent::validateTransaction($object, $type, $xactions);
|
||||
|
||||
switch ($type) {
|
||||
case NuanceSourceTransaction::TYPE_NAME:
|
||||
$missing = $this->validateIsEmptyTextField(
|
||||
$object->getName(),
|
||||
$xactions);
|
||||
|
||||
if ($missing) {
|
||||
$error = new PhabricatorApplicationTransactionValidationError(
|
||||
$type,
|
||||
pht('Required'),
|
||||
pht('Source name is required.'),
|
||||
nonempty(last($xactions), null));
|
||||
|
||||
$error->setIsMissingFieldError(true);
|
||||
$errors[] = $error;
|
||||
}
|
||||
break;
|
||||
case NuanceSourceTransaction::TYPE_DEFAULT_QUEUE:
|
||||
foreach ($xactions as $xaction) {
|
||||
if (!$xaction->getNewValue()) {
|
||||
$error = new PhabricatorApplicationTransactionValidationError(
|
||||
$type,
|
||||
pht('Required'),
|
||||
pht('Sources must have a default queue.'),
|
||||
$xaction);
|
||||
$error->setIsMissingFieldError(true);
|
||||
$errors[] = $error;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return $errors;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
54
src/applications/nuance/item/NuanceFormItemType.php
Normal file
54
src/applications/nuance/item/NuanceFormItemType.php
Normal file
|
@ -0,0 +1,54 @@
|
|||
<?php
|
||||
|
||||
final class NuanceFormItemType
|
||||
extends NuanceItemType {
|
||||
|
||||
const ITEMTYPE = 'form.item';
|
||||
|
||||
public function getItemTypeDisplayName() {
|
||||
return pht('Form');
|
||||
}
|
||||
|
||||
public function getItemDisplayName(NuanceItem $item) {
|
||||
return pht('Complaint');
|
||||
}
|
||||
|
||||
protected function newWorkCommands(NuanceItem $item) {
|
||||
return array(
|
||||
$this->newCommand('trash')
|
||||
->setIcon('fa-trash')
|
||||
->setName(pht('Throw In Trash')),
|
||||
);
|
||||
}
|
||||
|
||||
protected function newItemView(NuanceItem $item) {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$content = $item->getItemProperty('complaint');
|
||||
$content_view = id(new PHUIRemarkupView($viewer, $content))
|
||||
->setContextObject($item);
|
||||
|
||||
$content_section = id(new PHUIPropertyListView())
|
||||
->addTextContent(
|
||||
phutil_tag(
|
||||
'div',
|
||||
array(
|
||||
'class' => 'phabricator-remarkup',
|
||||
),
|
||||
$content_view));
|
||||
|
||||
$content_box = id(new PHUIObjectBoxView())
|
||||
->setHeaderText(pht('Complaint'))
|
||||
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
||||
->appendChild($content_section);
|
||||
|
||||
return array(
|
||||
$content_box,
|
||||
);
|
||||
}
|
||||
|
||||
protected function handleAction(NuanceItem $item, $action) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
|
@ -329,6 +329,9 @@ final class NuanceGitHubEventItemType
|
|||
NuanceItem $item,
|
||||
NuanceItemCommand $command) {
|
||||
|
||||
// TODO: This code is no longer reachable, and has moved to
|
||||
// CommandImplementation subclasses.
|
||||
|
||||
$action = $command->getCommand();
|
||||
switch ($action) {
|
||||
case 'sync':
|
||||
|
|
|
@ -32,6 +32,10 @@ abstract class NuanceItemType
|
|||
return $this->newItemView($item);
|
||||
}
|
||||
|
||||
final public function buildItemWorkView(NuanceItem $item) {
|
||||
return $this->newItemView($item);
|
||||
}
|
||||
|
||||
protected function newItemView(NuanceItem $item) {
|
||||
return null;
|
||||
}
|
||||
|
@ -91,57 +95,15 @@ abstract class NuanceItemType
|
|||
}
|
||||
|
||||
final public function buildActionResponse(NuanceItem $item, $action) {
|
||||
$response = $this->handleAction($item, $action);
|
||||
|
||||
if ($response === null) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
return $response;
|
||||
return $this->handleAction($item, $action);
|
||||
}
|
||||
|
||||
protected function handleAction(NuanceItem $item, $action) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final public function applyCommand(
|
||||
NuanceItem $item,
|
||||
NuanceItemCommand $command) {
|
||||
|
||||
$result = $this->handleCommand($item, $command);
|
||||
|
||||
if ($result === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$xaction = id(new NuanceItemTransaction())
|
||||
->setTransactionType(NuanceItemTransaction::TYPE_COMMAND)
|
||||
->setNewValue(
|
||||
array(
|
||||
'command' => $command->getCommand(),
|
||||
'parameters' => $command->getParameters(),
|
||||
'result' => $result,
|
||||
));
|
||||
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
// TODO: Maybe preserve the actor's original content source?
|
||||
$source = PhabricatorContentSource::newForSource(
|
||||
PhabricatorDaemonContentSource::SOURCECONST);
|
||||
|
||||
$editor = id(new NuanceItemEditor())
|
||||
->setActor($viewer)
|
||||
->setActingAsPHID($command->getAuthorPHID())
|
||||
->setContentSource($source)
|
||||
->setContinueOnMissingFields(true)
|
||||
->setContinueOnNoEffect(true)
|
||||
->applyTransactions($item, array($xaction));
|
||||
}
|
||||
|
||||
protected function handleCommand(
|
||||
NuanceItem $item,
|
||||
NuanceItemCommand $command) {
|
||||
return null;
|
||||
final public function buildWorkCommands(NuanceItem $item) {
|
||||
return $this->newWorkCommands($item);
|
||||
}
|
||||
|
||||
final protected function newContentSource(
|
||||
|
@ -159,4 +121,8 @@ abstract class NuanceItemType
|
|||
return id(new PhabricatorNuanceApplication())->getPHID();
|
||||
}
|
||||
|
||||
protected function newCommand($command_key) {
|
||||
return id(new NuanceItemCommandSpec())
|
||||
->setCommandKey($command_key);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ final class NuanceItemPHIDType extends PhabricatorPHIDType {
|
|||
foreach ($handles as $phid => $handle) {
|
||||
$item = $objects[$phid];
|
||||
|
||||
$handle->setName($item->getItemDisplayName());
|
||||
$handle->setName($item->getDisplayName());
|
||||
$handle->setURI($item->getURI());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ final class NuanceItemCommandQuery
|
|||
|
||||
private $ids;
|
||||
private $itemPHIDs;
|
||||
private $statuses;
|
||||
|
||||
public function withIDs(array $ids) {
|
||||
$this->ids = $ids;
|
||||
|
@ -16,6 +17,11 @@ final class NuanceItemCommandQuery
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function withStatuses(array $statuses) {
|
||||
$this->statuses = $statuses;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function newResultObject() {
|
||||
return new NuanceItemCommand();
|
||||
}
|
||||
|
@ -41,6 +47,13 @@ final class NuanceItemCommandQuery
|
|||
$this->itemPHIDs);
|
||||
}
|
||||
|
||||
if ($this->statuses !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'status IN (%Ls)',
|
||||
$this->statuses);
|
||||
}
|
||||
|
||||
return $where;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,9 +6,11 @@ final class NuanceItemQuery
|
|||
private $ids;
|
||||
private $phids;
|
||||
private $sourcePHIDs;
|
||||
private $queuePHIDs;
|
||||
private $itemTypes;
|
||||
private $itemKeys;
|
||||
private $containerKeys;
|
||||
private $statuses;
|
||||
|
||||
public function withIDs(array $ids) {
|
||||
$this->ids = $ids;
|
||||
|
@ -25,6 +27,11 @@ final class NuanceItemQuery
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function withQueuePHIDs(array $queue_phids) {
|
||||
$this->queuePHIDs = $queue_phids;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withItemTypes(array $item_types) {
|
||||
$this->itemTypes = $item_types;
|
||||
return $this;
|
||||
|
@ -35,6 +42,11 @@ final class NuanceItemQuery
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function withStatuses(array $statuses) {
|
||||
$this->statuses = $statuses;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withItemContainerKeys(array $container_keys) {
|
||||
$this->containerKeys = $container_keys;
|
||||
return $this;
|
||||
|
@ -49,13 +61,11 @@ final class NuanceItemQuery
|
|||
}
|
||||
|
||||
protected function willFilterPage(array $items) {
|
||||
$viewer = $this->getViewer();
|
||||
$source_phids = mpull($items, 'getSourcePHID');
|
||||
|
||||
// NOTE: We always load sources, even if the viewer can't formally see
|
||||
// them. If they can see the item, they're allowed to be aware of the
|
||||
// source in some sense.
|
||||
$sources = id(new NuanceSourceQuery())
|
||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||
->setViewer($viewer)
|
||||
->withPHIDs($source_phids)
|
||||
->execute();
|
||||
$sources = mpull($sources, null, 'getPHID');
|
||||
|
@ -81,6 +91,43 @@ final class NuanceItemQuery
|
|||
$item->attachImplementation($type);
|
||||
}
|
||||
|
||||
$queue_phids = array();
|
||||
foreach ($items as $item) {
|
||||
$queue_phid = $item->getQueuePHID();
|
||||
if ($queue_phid) {
|
||||
$queue_phids[$queue_phid] = $queue_phid;
|
||||
}
|
||||
}
|
||||
|
||||
if ($queue_phids) {
|
||||
$queues = id(new NuanceQueueQuery())
|
||||
->setViewer($viewer)
|
||||
->withPHIDs($queue_phids)
|
||||
->execute();
|
||||
$queues = mpull($queues, null, 'getPHID');
|
||||
} else {
|
||||
$queues = array();
|
||||
}
|
||||
|
||||
foreach ($items as $key => $item) {
|
||||
$queue_phid = $item->getQueuePHID();
|
||||
|
||||
if (!$queue_phid) {
|
||||
$item->attachQueue(null);
|
||||
continue;
|
||||
}
|
||||
|
||||
$queue = idx($queues, $queue_phid);
|
||||
|
||||
if (!$queue) {
|
||||
unset($items[$key]);
|
||||
$this->didRejectResult($item);
|
||||
continue;
|
||||
}
|
||||
|
||||
$item->attachQueue($queue);
|
||||
}
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
|
@ -94,6 +141,13 @@ final class NuanceItemQuery
|
|||
$this->sourcePHIDs);
|
||||
}
|
||||
|
||||
if ($this->queuePHIDs !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'queuePHID IN (%Ls)',
|
||||
$this->queuePHIDs);
|
||||
}
|
||||
|
||||
if ($this->ids !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
|
@ -108,6 +162,13 @@ final class NuanceItemQuery
|
|||
$this->phids);
|
||||
}
|
||||
|
||||
if ($this->statuses !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'status IN (%Ls)',
|
||||
$this->statuses);
|
||||
}
|
||||
|
||||
if ($this->itemTypes !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
|
|
|
@ -72,6 +72,19 @@ final class NuanceItemSearchEngine
|
|||
$impl->getItemTypeDisplayIcon(),
|
||||
$impl->getItemTypeDisplayName());
|
||||
|
||||
$queue = $item->getQueue();
|
||||
if ($queue) {
|
||||
$view->addAttribute(
|
||||
phutil_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => $queue->getURI(),
|
||||
),
|
||||
$queue->getName()));
|
||||
} else {
|
||||
$view->addAttribute(phutil_tag('em', array(), pht('Not in Queue')));
|
||||
}
|
||||
|
||||
$list->addItem($view);
|
||||
}
|
||||
|
||||
|
|
|
@ -39,6 +39,8 @@ final class NuancePhabricatorFormSourceDefinition
|
|||
$content_source = PhabricatorContentSource::newFromRequest($request);
|
||||
|
||||
$item = $this->newItemFromProperties(
|
||||
NuanceFormItemType::ITEMTYPE,
|
||||
$viewer->getPHID(),
|
||||
$properties,
|
||||
$content_source);
|
||||
|
||||
|
@ -79,7 +81,7 @@ final class NuancePhabricatorFormSourceDefinition
|
|||
NuanceItem $item,
|
||||
PHUIPropertyListView $view) {
|
||||
|
||||
$complaint = $item->getNuanceProperty('complaint');
|
||||
$complaint = $item->getItemProperty('complaint');
|
||||
$complaint = new PHUIRemarkupView($viewer, $complaint);
|
||||
$view->addSectionHeader(
|
||||
pht('Complaint'), 'fa-exclamation-circle');
|
||||
|
|
|
@ -149,6 +149,8 @@ abstract class NuanceSourceDefinition extends Phobject {
|
|||
}
|
||||
|
||||
protected function newItemFromProperties(
|
||||
$item_type,
|
||||
$author_phid,
|
||||
array $properties,
|
||||
PhabricatorContentSource $content_source) {
|
||||
|
||||
|
@ -157,29 +159,31 @@ abstract class NuanceSourceDefinition extends Phobject {
|
|||
$actor = PhabricatorUser::getOmnipotentUser();
|
||||
$source = $this->getSource();
|
||||
|
||||
$item = NuanceItem::initializeNewItem();
|
||||
$item = NuanceItem::initializeNewItem($item_type);
|
||||
|
||||
$xactions = array();
|
||||
|
||||
$xactions[] = id(new NuanceItemTransaction())
|
||||
->setTransactionType(NuanceItemTransaction::TYPE_SOURCE)
|
||||
->setTransactionType(NuanceItemSourceTransaction::TRANSACTIONTYPE)
|
||||
->setNewValue($source->getPHID());
|
||||
|
||||
// TODO: Eventually, apply real routing rules. For now, just put everything
|
||||
// in the default queue for the source.
|
||||
$xactions[] = id(new NuanceItemTransaction())
|
||||
->setTransactionType(NuanceItemTransaction::TYPE_QUEUE)
|
||||
->setTransactionType(NuanceItemQueueTransaction::TRANSACTIONTYPE)
|
||||
->setNewValue($source->getDefaultQueuePHID());
|
||||
|
||||
// TODO: Maybe this should all be modular transactions now?
|
||||
foreach ($properties as $key => $property) {
|
||||
$xactions[] = id(new NuanceItemTransaction())
|
||||
->setTransactionType(NuanceItemTransaction::TYPE_PROPERTY)
|
||||
->setTransactionType(NuanceItemPropertyTransaction::TRANSACTIONTYPE)
|
||||
->setMetadataValue(NuanceItemTransaction::PROPERTY_KEY, $key)
|
||||
->setNewValue($property);
|
||||
}
|
||||
|
||||
$editor = id(new NuanceItemEditor())
|
||||
->setActor($actor)
|
||||
->setActingAsPHID($author_phid)
|
||||
->setContentSource($content_source);
|
||||
|
||||
$editor->applyTransactions($item, $xactions);
|
||||
|
|
|
@ -9,7 +9,6 @@ final class NuanceItem
|
|||
const STATUS_IMPORTING = 'importing';
|
||||
const STATUS_ROUTING = 'routing';
|
||||
const STATUS_OPEN = 'open';
|
||||
const STATUS_ASSIGNED = 'assigned';
|
||||
const STATUS_CLOSED = 'closed';
|
||||
|
||||
protected $status;
|
||||
|
@ -23,11 +22,16 @@ final class NuanceItem
|
|||
protected $data = array();
|
||||
protected $mailKey;
|
||||
|
||||
private $queue = self::ATTACHABLE;
|
||||
private $source = self::ATTACHABLE;
|
||||
private $implementation = self::ATTACHABLE;
|
||||
|
||||
public static function initializeNewItem() {
|
||||
public static function initializeNewItem($item_type) {
|
||||
|
||||
// TODO: Validate that the type is valid, and construct and attach it.
|
||||
|
||||
return id(new NuanceItem())
|
||||
->setItemType($item_type)
|
||||
->setStatus(self::STATUS_OPEN);
|
||||
}
|
||||
|
||||
|
@ -42,7 +46,7 @@ final class NuanceItem
|
|||
'requestorPHID' => 'phid?',
|
||||
'queuePHID' => 'phid?',
|
||||
'itemType' => 'text64',
|
||||
'itemKey' => 'text64',
|
||||
'itemKey' => 'text64?',
|
||||
'itemContainerKey' => 'text64?',
|
||||
'status' => 'text32',
|
||||
'mailKey' => 'bytes20',
|
||||
|
@ -172,6 +176,15 @@ final class NuanceItem
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function getQueue() {
|
||||
return $this->assertAttached($this->queue);
|
||||
}
|
||||
|
||||
public function attachQueue(NuanceQueue $queue = null) {
|
||||
$this->queue = $queue;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/* -( PhabricatorApplicationTransactionInterface )------------------------- */
|
||||
|
||||
|
|
|
@ -4,32 +4,86 @@ final class NuanceItemCommand
|
|||
extends NuanceDAO
|
||||
implements PhabricatorPolicyInterface {
|
||||
|
||||
const STATUS_ISSUED = 'issued';
|
||||
const STATUS_EXECUTING = 'executing';
|
||||
const STATUS_DONE = 'done';
|
||||
const STATUS_FAILED = 'failed';
|
||||
|
||||
protected $itemPHID;
|
||||
protected $authorPHID;
|
||||
protected $queuePHID;
|
||||
protected $command;
|
||||
protected $parameters;
|
||||
protected $status;
|
||||
protected $parameters = array();
|
||||
|
||||
public static function initializeNewCommand() {
|
||||
return new self();
|
||||
return id(new self())
|
||||
->setStatus(self::STATUS_ISSUED);
|
||||
}
|
||||
|
||||
protected function getConfiguration() {
|
||||
return array(
|
||||
self::CONFIG_TIMESTAMPS => false,
|
||||
self::CONFIG_SERIALIZATION => array(
|
||||
'parameters' => self::SERIALIZATION_JSON,
|
||||
),
|
||||
self::CONFIG_COLUMN_SCHEMA => array(
|
||||
'command' => 'text64',
|
||||
'status' => 'text64',
|
||||
'queuePHID' => 'phid?',
|
||||
),
|
||||
self::CONFIG_KEY_SCHEMA => array(
|
||||
'key_item' => array(
|
||||
'columns' => array('itemPHID'),
|
||||
'key_pending' => array(
|
||||
'columns' => array('itemPHID', 'status'),
|
||||
),
|
||||
),
|
||||
) + parent::getConfiguration();
|
||||
}
|
||||
|
||||
public static function getStatusMap() {
|
||||
return array(
|
||||
self::STATUS_ISSUED => array(
|
||||
'name' => pht('Issued'),
|
||||
'icon' => 'fa-clock-o',
|
||||
'color' => 'bluegrey',
|
||||
),
|
||||
self::STATUS_EXECUTING => array(
|
||||
'name' => pht('Executing'),
|
||||
'icon' => 'fa-play',
|
||||
'color' => 'green',
|
||||
),
|
||||
self::STATUS_DONE => array(
|
||||
'name' => pht('Done'),
|
||||
'icon' => 'fa-check',
|
||||
'color' => 'blue',
|
||||
),
|
||||
self::STATUS_FAILED => array(
|
||||
'name' => pht('Failed'),
|
||||
'icon' => 'fa-times',
|
||||
'color' => 'red',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
private function getStatusSpec() {
|
||||
$map = self::getStatusMap();
|
||||
return idx($map, $this->getStatus(), array());
|
||||
}
|
||||
|
||||
public function getStatusIcon() {
|
||||
$spec = $this->getStatusSpec();
|
||||
return idx($spec, 'icon', 'fa-question');
|
||||
}
|
||||
|
||||
public function getStatusColor() {
|
||||
$spec = $this->getStatusSpec();
|
||||
return idx($spec, 'color', 'indigo');
|
||||
}
|
||||
|
||||
public function getStatusName() {
|
||||
$spec = $this->getStatusSpec();
|
||||
return idx($spec, 'name', $this->getStatus());
|
||||
}
|
||||
|
||||
|
||||
/* -( PhabricatorPolicyInterface )----------------------------------------- */
|
||||
|
||||
|
|
|
@ -5,13 +5,6 @@ final class NuanceItemTransaction
|
|||
|
||||
const PROPERTY_KEY = 'property.key';
|
||||
|
||||
const TYPE_OWNER = 'nuance.item.owner';
|
||||
const TYPE_REQUESTOR = 'nuance.item.requestor';
|
||||
const TYPE_SOURCE = 'nuance.item.source';
|
||||
const TYPE_PROPERTY = 'nuance.item.property';
|
||||
const TYPE_QUEUE = 'nuance.item.queue';
|
||||
const TYPE_COMMAND = 'nuance.item.command';
|
||||
|
||||
public function getApplicationTransactionType() {
|
||||
return NuanceItemPHIDType::TYPECONST;
|
||||
}
|
||||
|
@ -20,61 +13,8 @@ final class NuanceItemTransaction
|
|||
return new NuanceItemTransactionComment();
|
||||
}
|
||||
|
||||
public function shouldHide() {
|
||||
$old = $this->getOldValue();
|
||||
$type = $this->getTransactionType();
|
||||
|
||||
switch ($type) {
|
||||
case self::TYPE_REQUESTOR:
|
||||
case self::TYPE_SOURCE:
|
||||
return ($old === null);
|
||||
}
|
||||
|
||||
return parent::shouldHide();
|
||||
}
|
||||
|
||||
public function getRequiredHandlePHIDs() {
|
||||
$old = $this->getOldValue();
|
||||
$new = $this->getNewValue();
|
||||
$type = $this->getTransactionType();
|
||||
|
||||
$phids = parent::getRequiredHandlePHIDs();
|
||||
switch ($type) {
|
||||
case self::TYPE_QUEUE:
|
||||
if ($old) {
|
||||
$phids[] = $old;
|
||||
}
|
||||
if ($new) {
|
||||
$phids[] = $new;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return $phids;
|
||||
}
|
||||
|
||||
public function getTitle() {
|
||||
$old = $this->getOldValue();
|
||||
$new = $this->getNewValue();
|
||||
$type = $this->getTransactionType();
|
||||
|
||||
$author_phid = $this->getAuthorPHID();
|
||||
|
||||
switch ($type) {
|
||||
case self::TYPE_QUEUE:
|
||||
return pht(
|
||||
'%s routed this item to the %s queue.',
|
||||
$this->renderHandleLink($author_phid),
|
||||
$this->renderHandleLink($new));
|
||||
case self::TYPE_COMMAND:
|
||||
// TODO: Give item types a chance to render this properly.
|
||||
return pht(
|
||||
'%s applied command "%s" to this item.',
|
||||
$this->renderHandleLink($author_phid),
|
||||
idx($new, 'command'));
|
||||
}
|
||||
|
||||
return parent::getTitle();
|
||||
public function getBaseTransactionClass() {
|
||||
return 'NuanceItemTransactionType';
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -43,6 +43,10 @@ final class NuanceQueue
|
|||
return '/nuance/queue/view/'.$this->getID().'/';
|
||||
}
|
||||
|
||||
public function getWorkURI() {
|
||||
return '/nuance/queue/work/'.$this->getID().'/';
|
||||
}
|
||||
|
||||
|
||||
/* -( PhabricatorPolicyInterface )----------------------------------------- */
|
||||
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
|
||||
final class NuanceQueueTransaction extends NuanceTransaction {
|
||||
|
||||
const TYPE_NAME = 'nuance.queue.name';
|
||||
|
||||
public function getApplicationTransactionType() {
|
||||
return NuanceQueuePHIDType::TYPECONST;
|
||||
}
|
||||
|
@ -12,26 +10,8 @@ final class NuanceQueueTransaction extends NuanceTransaction {
|
|||
return new NuanceQueueTransactionComment();
|
||||
}
|
||||
|
||||
public function getTitle() {
|
||||
$old = $this->getOldValue();
|
||||
$new = $this->getNewValue();
|
||||
$type = $this->getTransactionType();
|
||||
|
||||
$author_phid = $this->getAuthorPHID();
|
||||
|
||||
switch ($type) {
|
||||
case PhabricatorTransactions::TYPE_CREATE:
|
||||
return pht(
|
||||
'%s created this queue.',
|
||||
$this->renderHandleLink($author_phid));
|
||||
case self::TYPE_NAME:
|
||||
return pht(
|
||||
'%s renamed this queue from "%s" to "%s".',
|
||||
$this->renderHandleLink($author_phid),
|
||||
$old,
|
||||
$new);
|
||||
}
|
||||
|
||||
return parent::getTitle();
|
||||
public function getBaseTransactionClass() {
|
||||
return 'NuanceQueueTransactionType';
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,9 +3,6 @@
|
|||
final class NuanceSourceTransaction
|
||||
extends NuanceTransaction {
|
||||
|
||||
const TYPE_NAME = 'source.name';
|
||||
const TYPE_DEFAULT_QUEUE = 'source.queue.default';
|
||||
|
||||
public function getApplicationTransactionType() {
|
||||
return NuanceSourcePHIDType::TYPECONST;
|
||||
}
|
||||
|
@ -14,63 +11,8 @@ final class NuanceSourceTransaction
|
|||
return new NuanceSourceTransactionComment();
|
||||
}
|
||||
|
||||
public function shouldHide() {
|
||||
$old = $this->getOldValue();
|
||||
$new = $this->getNewValue();
|
||||
$type = $this->getTransactionType();
|
||||
|
||||
switch ($type) {
|
||||
case self::TYPE_DEFAULT_QUEUE:
|
||||
return !$old;
|
||||
case self::TYPE_NAME:
|
||||
return ($old === null);
|
||||
}
|
||||
|
||||
return parent::shouldHide();
|
||||
}
|
||||
|
||||
public function getRequiredHandlePHIDs() {
|
||||
$old = $this->getOldValue();
|
||||
$new = $this->getNewValue();
|
||||
$type = $this->getTransactionType();
|
||||
|
||||
$phids = parent::getRequiredHandlePHIDs();
|
||||
switch ($type) {
|
||||
case self::TYPE_DEFAULT_QUEUE:
|
||||
if ($old) {
|
||||
$phids[] = $old;
|
||||
}
|
||||
if ($new) {
|
||||
$phids[] = $new;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return $phids;
|
||||
}
|
||||
|
||||
public function getTitle() {
|
||||
$old = $this->getOldValue();
|
||||
$new = $this->getNewValue();
|
||||
$type = $this->getTransactionType();
|
||||
$author_phid = $this->getAuthorPHID();
|
||||
|
||||
switch ($type) {
|
||||
case self::TYPE_DEFAULT_QUEUE:
|
||||
return pht(
|
||||
'%s changed the default queue from %s to %s.',
|
||||
$this->renderHandleLink($author_phid),
|
||||
$this->renderHandleLink($old),
|
||||
$this->renderHandleLink($new));
|
||||
case self::TYPE_NAME:
|
||||
return pht(
|
||||
'%s renamed this source from "%s" to "%s".',
|
||||
$this->renderHandleLink($author_phid),
|
||||
$old,
|
||||
$new);
|
||||
}
|
||||
|
||||
return parent::getTitle();
|
||||
public function getBaseTransactionClass() {
|
||||
return 'NuanceSourceTransactionType';
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
abstract class NuanceTransaction
|
||||
extends PhabricatorApplicationTransaction {
|
||||
extends PhabricatorModularTransaction {
|
||||
|
||||
public function getApplicationName() {
|
||||
return 'nuance';
|
||||
|
|
|
@ -6,9 +6,7 @@ final class NuanceItemUpdateWorker
|
|||
protected function doWork() {
|
||||
$item_phid = $this->getTaskDataValue('itemPHID');
|
||||
|
||||
$hash = PhabricatorHash::digestForIndex($item_phid);
|
||||
$lock_key = "nuance.item.{$hash}";
|
||||
$lock = PhabricatorGlobalLock::newLock($lock_key);
|
||||
$lock = $this->newLock($item_phid);
|
||||
|
||||
$lock->lock(1);
|
||||
try {
|
||||
|
@ -55,19 +53,109 @@ final class NuanceItemUpdateWorker
|
|||
private function applyCommands(NuanceItem $item) {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$impl = $item->getImplementation();
|
||||
$impl->setViewer($viewer);
|
||||
|
||||
$commands = id(new NuanceItemCommandQuery())
|
||||
->setViewer($viewer)
|
||||
->withItemPHIDs(array($item->getPHID()))
|
||||
->withStatuses(
|
||||
array(
|
||||
NuanceItemCommand::STATUS_ISSUED,
|
||||
))
|
||||
->execute();
|
||||
$commands = msort($commands, 'getID');
|
||||
|
||||
$this->executeCommandList($item, $commands);
|
||||
}
|
||||
|
||||
public function executeCommands(NuanceItem $item, array $commands) {
|
||||
if (!$commands) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$item_phid = $item->getPHID();
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$lock = $this->newLock($item_phid);
|
||||
try {
|
||||
$lock->lock(1);
|
||||
} catch (PhutilLockException $ex) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
$item = $this->loadItem($item_phid);
|
||||
|
||||
// Reload commands now that we have a lock, to make sure we don't
|
||||
// execute any commands twice by mistake.
|
||||
$commands = id(new NuanceItemCommandQuery())
|
||||
->setViewer($viewer)
|
||||
->withIDs(mpull($commands, 'getID'))
|
||||
->execute();
|
||||
|
||||
$this->executeCommandList($item, $commands);
|
||||
} catch (Exception $ex) {
|
||||
$lock->unlock();
|
||||
throw $ex;
|
||||
}
|
||||
|
||||
$lock->unlock();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function executeCommandList(NuanceItem $item, array $commands) {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$executors = NuanceCommandImplementation::getAllCommands();
|
||||
foreach ($commands as $command) {
|
||||
$impl->applyCommand($item, $command);
|
||||
$command->delete();
|
||||
if ($command->getItemPHID() !== $item->getPHID()) {
|
||||
throw new Exception(
|
||||
pht('Trying to apply a command to the wrong item!'));
|
||||
}
|
||||
|
||||
if ($command->getStatus() !== NuanceItemCommand::STATUS_ISSUED) {
|
||||
// Never execute commands which have already been issued.
|
||||
continue;
|
||||
}
|
||||
|
||||
$command
|
||||
->setStatus(NuanceItemCommand::STATUS_EXECUTING)
|
||||
->save();
|
||||
|
||||
try {
|
||||
$command_key = $command->getCommand();
|
||||
|
||||
$executor = idx($executors, $command_key);
|
||||
if (!$executor) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Unable to execute command "%s": this command does not have '.
|
||||
'a recognized command implementation.',
|
||||
$command_key));
|
||||
}
|
||||
|
||||
$executor = clone $executor;
|
||||
|
||||
$executor
|
||||
->setActor($viewer)
|
||||
->applyCommand($item, $command);
|
||||
|
||||
$command
|
||||
->setStatus(NuanceItemCommand::STATUS_DONE)
|
||||
->save();
|
||||
} catch (Exception $ex) {
|
||||
$command
|
||||
->setStatus(NuanceItemCommand::STATUS_FAILED)
|
||||
->save();
|
||||
|
||||
throw $ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function newLock($item_phid) {
|
||||
$hash = PhabricatorHash::digestForIndex($item_phid);
|
||||
$lock_key = "nuance.item.{$hash}";
|
||||
return PhabricatorGlobalLock::newLock($lock_key);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
final class NuanceItemCommandTransaction
|
||||
extends NuanceItemTransactionType {
|
||||
|
||||
const TRANSACTIONTYPE = 'nuance.item.command';
|
||||
|
||||
public function generateOldValue($object) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getTitle() {
|
||||
$spec = $this->getNewValue();
|
||||
$command_key = idx($spec, 'command', '???');
|
||||
|
||||
return pht(
|
||||
'%s applied a "%s" command to this item.',
|
||||
$this->renderAuthor(),
|
||||
$command_key);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
final class NuanceItemOwnerTransaction
|
||||
extends NuanceItemTransactionType {
|
||||
|
||||
const TRANSACTIONTYPE = 'nuance.item.owner';
|
||||
|
||||
public function generateOldValue($object) {
|
||||
return $object->getOwnerPHID();
|
||||
}
|
||||
|
||||
public function applyInternalEffects($object, $value) {
|
||||
$object->setOwnerPHID($value);
|
||||
}
|
||||
|
||||
public function getTitle() {
|
||||
|
||||
// TODO: Assign, unassign strings probably need variants.
|
||||
|
||||
return pht(
|
||||
'%s reassigned this item from %s to %s.',
|
||||
$this->renderAuthor(),
|
||||
$this->renderHandle($this->getOldValue()),
|
||||
$this->renderHandle($this->getNewValue()));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
final class NuanceItemPropertyTransaction
|
||||
extends NuanceItemTransactionType {
|
||||
|
||||
const TRANSACTIONTYPE = 'nuance.item.property';
|
||||
|
||||
public function generateOldValue($object) {
|
||||
$property_key = NuanceItemTransaction::PROPERTY_KEY;
|
||||
$key = $this->getMetadataValue($property_key);
|
||||
return $object->getItemProperty($key);
|
||||
}
|
||||
|
||||
public function applyInternalEffects($object, $value) {
|
||||
$property_key = NuanceItemTransaction::PROPERTY_KEY;
|
||||
$key = $this->getMetadataValue($property_key);
|
||||
|
||||
$object->setItemProperty($key, $value);
|
||||
}
|
||||
|
||||
public function getTitle() {
|
||||
return pht(
|
||||
'%s set a property on this item.',
|
||||
$this->renderAuthor());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
final class NuanceItemQueueTransaction
|
||||
extends NuanceItemTransactionType {
|
||||
|
||||
const TRANSACTIONTYPE = 'nuance.item.queue';
|
||||
|
||||
public function generateOldValue($object) {
|
||||
return $object->getQueuePHID();
|
||||
}
|
||||
|
||||
public function applyInternalEffects($object, $value) {
|
||||
$object->setQueuePHID($value);
|
||||
}
|
||||
|
||||
public function getTitle() {
|
||||
return pht(
|
||||
'%s rerouted this item from %s to %s.',
|
||||
$this->renderAuthor(),
|
||||
$this->renderHandle($this->getOldValue()),
|
||||
$this->renderHandle($this->getNewValue()));
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
final class NuanceItemRequestorTransaction
|
||||
extends NuanceItemTransactionType {
|
||||
|
||||
const TRANSACTIONTYPE = 'nuance.item.requestor';
|
||||
|
||||
public function generateOldValue($object) {
|
||||
return $object->getRequestorPHID();
|
||||
}
|
||||
|
||||
public function applyInternalEffects($object, $value) {
|
||||
$object->setRequestorPHID($value);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
final class NuanceItemSourceTransaction
|
||||
extends NuanceItemTransactionType {
|
||||
|
||||
const TRANSACTIONTYPE = 'nuance.item.source';
|
||||
|
||||
public function generateOldValue($object) {
|
||||
return $object->getSourcePHID();
|
||||
}
|
||||
|
||||
public function applyInternalEffects($object, $value) {
|
||||
$object->setSourcePHID($value);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
final class NuanceItemStatusTransaction
|
||||
extends NuanceItemTransactionType {
|
||||
|
||||
const TRANSACTIONTYPE = 'nuance.item.status';
|
||||
|
||||
public function generateOldValue($object) {
|
||||
return $object->getStatus();
|
||||
}
|
||||
|
||||
public function applyInternalEffects($object, $value) {
|
||||
$object->setStatus($value);
|
||||
}
|
||||
|
||||
public function getTitle() {
|
||||
return pht(
|
||||
'%s changed the status of this item from %s to %s.',
|
||||
$this->renderAuthor(),
|
||||
$this->renderOldValue(),
|
||||
$this->renderNewValue());
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
<?php
|
||||
|
||||
abstract class NuanceItemTransactionType
|
||||
extends PhabricatorModularTransactionType {}
|
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
|
||||
final class NuanceQueueNameTransaction
|
||||
extends NuanceQueueTransactionType {
|
||||
|
||||
const TRANSACTIONTYPE = 'nuance.queue.name';
|
||||
|
||||
public function generateOldValue($object) {
|
||||
return $object->getName();
|
||||
}
|
||||
|
||||
public function applyInternalEffects($object, $value) {
|
||||
$object->setName($value);
|
||||
}
|
||||
|
||||
public function getTitle() {
|
||||
return pht(
|
||||
'%s renamed this queue from %s to %s.',
|
||||
$this->renderAuthor(),
|
||||
$this->renderOldValue(),
|
||||
$this->renderNewValue());
|
||||
}
|
||||
|
||||
public function validateTransactions($object, array $xactions) {
|
||||
$errors = array();
|
||||
|
||||
if ($this->isEmptyTextTransaction($object->getName(), $xactions)) {
|
||||
$errors[] = $this->newRequiredError(
|
||||
pht('Queues must have a name.'));
|
||||
}
|
||||
|
||||
$max_length = $object->getColumnMaximumByteLength('name');
|
||||
foreach ($xactions as $xaction) {
|
||||
$new_value = $xaction->getNewValue();
|
||||
$new_length = strlen($new_value);
|
||||
if ($new_length > $max_length) {
|
||||
$errors[] = $this->newInvalidError(
|
||||
pht(
|
||||
'Queue names must not be longer than %s character(s).',
|
||||
new PhutilNumber($max_length)));
|
||||
}
|
||||
}
|
||||
|
||||
return $errors;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
<?php
|
||||
|
||||
abstract class NuanceQueueTransactionType
|
||||
extends PhabricatorModularTransactionType {}
|
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
final class NuanceSourceDefaultQueueTransaction
|
||||
extends NuanceSourceTransactionType {
|
||||
|
||||
const TRANSACTIONTYPE = 'source.queue.default';
|
||||
|
||||
public function generateOldValue($object) {
|
||||
return $object->getDefaultQueuePHID();
|
||||
}
|
||||
|
||||
public function applyInternalEffects($object, $value) {
|
||||
$object->setDefaultQueuePHID($value);
|
||||
}
|
||||
|
||||
public function getTitle() {
|
||||
return pht(
|
||||
'%s changed the default queue for this source from %s to %s.',
|
||||
$this->renderAuthor(),
|
||||
$this->renderOldHandle(),
|
||||
$this->renderNewHandle());
|
||||
}
|
||||
|
||||
public function validateTransactions($object, array $xactions) {
|
||||
$errors = array();
|
||||
|
||||
if (!$object->getDefaultQueuePHID() && !$xactions) {
|
||||
$errors[] = $this->newRequiredError(
|
||||
pht('Sources must have a default queue.'));
|
||||
}
|
||||
|
||||
foreach ($xactions as $xaction) {
|
||||
if (!$xaction->getNewValue()) {
|
||||
$errors[] = $this->newRequiredError(
|
||||
pht('Sources must have a default queue.'));
|
||||
}
|
||||
}
|
||||
|
||||
return $errors;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
|
||||
final class NuanceSourceNameTransaction
|
||||
extends NuanceSourceTransactionType {
|
||||
|
||||
const TRANSACTIONTYPE = 'source.name';
|
||||
|
||||
public function generateOldValue($object) {
|
||||
return $object->getName();
|
||||
}
|
||||
|
||||
public function applyInternalEffects($object, $value) {
|
||||
$object->setName($value);
|
||||
}
|
||||
|
||||
public function getTitle() {
|
||||
return pht(
|
||||
'%s renamed this source from %s to %s.',
|
||||
$this->renderAuthor(),
|
||||
$this->renderOldValue(),
|
||||
$this->renderNewValue());
|
||||
}
|
||||
|
||||
public function validateTransactions($object, array $xactions) {
|
||||
$errors = array();
|
||||
|
||||
if ($this->isEmptyTextTransaction($object->getName(), $xactions)) {
|
||||
$errors[] = $this->newRequiredError(
|
||||
pht('Sources must have a name.'));
|
||||
}
|
||||
|
||||
$max_length = $object->getColumnMaximumByteLength('name');
|
||||
foreach ($xactions as $xaction) {
|
||||
$new_value = $xaction->getNewValue();
|
||||
$new_length = strlen($new_value);
|
||||
if ($new_length > $max_length) {
|
||||
$errors[] = $this->newInvalidError(
|
||||
pht(
|
||||
'Source names must not be longer than %s character(s).',
|
||||
new PhutilNumber($max_length)));
|
||||
}
|
||||
}
|
||||
|
||||
return $errors;
|
||||
}
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue