mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-02 03:32:42 +01:00
(stable) Promote 2015 Week 35
This commit is contained in:
commit
5125045738
55 changed files with 1115 additions and 206 deletions
|
@ -11,7 +11,7 @@ return array(
|
|||
'core.pkg.js' => 'a590b451',
|
||||
'darkconsole.pkg.js' => 'e7393ebb',
|
||||
'differential.pkg.css' => '2de124c9',
|
||||
'differential.pkg.js' => 'ebef29b1',
|
||||
'differential.pkg.js' => '813c1633',
|
||||
'diffusion.pkg.css' => '385e85b3',
|
||||
'diffusion.pkg.js' => '0115b37c',
|
||||
'maniphest.pkg.css' => '4845691a',
|
||||
|
@ -407,7 +407,7 @@ return array(
|
|||
'rsrc/js/application/releeph/releeph-preview-branch.js' => 'b2b4fbaf',
|
||||
'rsrc/js/application/releeph/releeph-request-state-change.js' => 'a0b57eb8',
|
||||
'rsrc/js/application/releeph/releeph-request-typeahead.js' => 'de2e896f',
|
||||
'rsrc/js/application/repository/repository-crossreference.js' => 'bea81850',
|
||||
'rsrc/js/application/repository/repository-crossreference.js' => 'e5339c43',
|
||||
'rsrc/js/application/search/behavior-reorder-queries.js' => 'e9581f08',
|
||||
'rsrc/js/application/slowvote/behavior-slowvote-embed.js' => '887ad43f',
|
||||
'rsrc/js/application/transactions/behavior-show-older-transactions.js' => 'dbbf48b6',
|
||||
|
@ -643,7 +643,7 @@ return array(
|
|||
'javelin-behavior-remarkup-preview' => 'f7379f45',
|
||||
'javelin-behavior-reorder-applications' => '76b9fc3e',
|
||||
'javelin-behavior-reorder-columns' => 'e1d25dfb',
|
||||
'javelin-behavior-repository-crossreference' => 'bea81850',
|
||||
'javelin-behavior-repository-crossreference' => 'e5339c43',
|
||||
'javelin-behavior-scrollbar' => '834a1173',
|
||||
'javelin-behavior-search-reorder-queries' => 'e9581f08',
|
||||
'javelin-behavior-select-on-click' => '4e3e79a6',
|
||||
|
@ -1745,12 +1745,6 @@ return array(
|
|||
'javelin-util',
|
||||
'phabricator-shaped-request',
|
||||
),
|
||||
'bea81850' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-dom',
|
||||
'javelin-stratcom',
|
||||
'javelin-uri',
|
||||
),
|
||||
'c1700f6f' => array(
|
||||
'javelin-install',
|
||||
'javelin-util',
|
||||
|
@ -1896,6 +1890,12 @@ return array(
|
|||
'javelin-behavior',
|
||||
'javelin-dom',
|
||||
),
|
||||
'e5339c43' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-dom',
|
||||
'javelin-stratcom',
|
||||
'javelin-uri',
|
||||
),
|
||||
'e5822781' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-dom',
|
||||
|
|
1
resources/sql/autopatches/20150823.nuance.queue.1.sql
Normal file
1
resources/sql/autopatches/20150823.nuance.queue.1.sql
Normal file
|
@ -0,0 +1 @@
|
|||
DROP TABLE {$NAMESPACE}_nuance.nuance_queueitem;
|
2
resources/sql/autopatches/20150823.nuance.queue.2.sql
Normal file
2
resources/sql/autopatches/20150823.nuance.queue.2.sql
Normal file
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE {$NAMESPACE}_nuance.nuance_item
|
||||
ADD queuePHID VARBINARY(64) NOT NULL;
|
2
resources/sql/autopatches/20150823.nuance.queue.3.sql
Normal file
2
resources/sql/autopatches/20150823.nuance.queue.3.sql
Normal file
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE {$NAMESPACE}_nuance.nuance_source
|
||||
ADD defaultQueuePHID VARBINARY(64) NOT NULL;
|
2
resources/sql/autopatches/20150823.nuance.queue.4.sql
Normal file
2
resources/sql/autopatches/20150823.nuance.queue.4.sql
Normal file
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE {$NAMESPACE}_nuance.nuance_item
|
||||
DROP dateNuanced;
|
|
@ -798,6 +798,7 @@ phutil_register_library_map(array(
|
|||
'DrydockBlueprintCoreCustomField' => 'applications/drydock/customfield/DrydockBlueprintCoreCustomField.php',
|
||||
'DrydockBlueprintCreateController' => 'applications/drydock/controller/DrydockBlueprintCreateController.php',
|
||||
'DrydockBlueprintCustomField' => 'applications/drydock/customfield/DrydockBlueprintCustomField.php',
|
||||
'DrydockBlueprintDatasource' => 'applications/drydock/typeahead/DrydockBlueprintDatasource.php',
|
||||
'DrydockBlueprintEditController' => 'applications/drydock/controller/DrydockBlueprintEditController.php',
|
||||
'DrydockBlueprintEditor' => 'applications/drydock/editor/DrydockBlueprintEditor.php',
|
||||
'DrydockBlueprintImplementation' => 'applications/drydock/blueprint/DrydockBlueprintImplementation.php',
|
||||
|
@ -822,6 +823,7 @@ phutil_register_library_map(array(
|
|||
'DrydockInterface' => 'applications/drydock/interface/DrydockInterface.php',
|
||||
'DrydockLease' => 'applications/drydock/storage/DrydockLease.php',
|
||||
'DrydockLeaseController' => 'applications/drydock/controller/DrydockLeaseController.php',
|
||||
'DrydockLeaseDatasource' => 'applications/drydock/typeahead/DrydockLeaseDatasource.php',
|
||||
'DrydockLeaseListController' => 'applications/drydock/controller/DrydockLeaseListController.php',
|
||||
'DrydockLeaseListView' => 'applications/drydock/view/DrydockLeaseListView.php',
|
||||
'DrydockLeasePHIDType' => 'applications/drydock/phid/DrydockLeasePHIDType.php',
|
||||
|
@ -847,6 +849,7 @@ phutil_register_library_map(array(
|
|||
'DrydockResource' => 'applications/drydock/storage/DrydockResource.php',
|
||||
'DrydockResourceCloseController' => 'applications/drydock/controller/DrydockResourceCloseController.php',
|
||||
'DrydockResourceController' => 'applications/drydock/controller/DrydockResourceController.php',
|
||||
'DrydockResourceDatasource' => 'applications/drydock/typeahead/DrydockResourceDatasource.php',
|
||||
'DrydockResourceListController' => 'applications/drydock/controller/DrydockResourceListController.php',
|
||||
'DrydockResourceListView' => 'applications/drydock/view/DrydockResourceListView.php',
|
||||
'DrydockResourcePHIDType' => 'applications/drydock/phid/DrydockResourcePHIDType.php',
|
||||
|
@ -1269,6 +1272,7 @@ phutil_register_library_map(array(
|
|||
'MultimeterSampleController' => 'applications/multimeter/controller/MultimeterSampleController.php',
|
||||
'MultimeterViewer' => 'applications/multimeter/storage/MultimeterViewer.php',
|
||||
'NuanceConduitAPIMethod' => 'applications/nuance/conduit/NuanceConduitAPIMethod.php',
|
||||
'NuanceConsoleController' => 'applications/nuance/controller/NuanceConsoleController.php',
|
||||
'NuanceController' => 'applications/nuance/controller/NuanceController.php',
|
||||
'NuanceCreateItemConduitAPIMethod' => 'applications/nuance/conduit/NuanceCreateItemConduitAPIMethod.php',
|
||||
'NuanceDAO' => 'applications/nuance/storage/NuanceDAO.php',
|
||||
|
@ -1284,9 +1288,9 @@ phutil_register_library_map(array(
|
|||
'NuancePhabricatorFormSourceDefinition' => 'applications/nuance/source/NuancePhabricatorFormSourceDefinition.php',
|
||||
'NuanceQuery' => 'applications/nuance/query/NuanceQuery.php',
|
||||
'NuanceQueue' => 'applications/nuance/storage/NuanceQueue.php',
|
||||
'NuanceQueueDatasource' => 'applications/nuance/typeahead/NuanceQueueDatasource.php',
|
||||
'NuanceQueueEditController' => 'applications/nuance/controller/NuanceQueueEditController.php',
|
||||
'NuanceQueueEditor' => 'applications/nuance/editor/NuanceQueueEditor.php',
|
||||
'NuanceQueueItem' => 'applications/nuance/storage/NuanceQueueItem.php',
|
||||
'NuanceQueueListController' => 'applications/nuance/controller/NuanceQueueListController.php',
|
||||
'NuanceQueuePHIDType' => 'applications/nuance/phid/NuanceQueuePHIDType.php',
|
||||
'NuanceQueueQuery' => 'applications/nuance/query/NuanceQueueQuery.php',
|
||||
|
@ -4478,6 +4482,7 @@ phutil_register_library_map(array(
|
|||
),
|
||||
'DrydockBlueprintCreateController' => 'DrydockBlueprintController',
|
||||
'DrydockBlueprintCustomField' => 'PhabricatorCustomField',
|
||||
'DrydockBlueprintDatasource' => 'PhabricatorTypeaheadDatasource',
|
||||
'DrydockBlueprintEditController' => 'DrydockBlueprintController',
|
||||
'DrydockBlueprintEditor' => 'PhabricatorApplicationTransactionEditor',
|
||||
'DrydockBlueprintImplementation' => 'Phobject',
|
||||
|
@ -4505,6 +4510,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorPolicyInterface',
|
||||
),
|
||||
'DrydockLeaseController' => 'DrydockController',
|
||||
'DrydockLeaseDatasource' => 'PhabricatorTypeaheadDatasource',
|
||||
'DrydockLeaseListController' => 'DrydockLeaseController',
|
||||
'DrydockLeaseListView' => 'AphrontView',
|
||||
'DrydockLeasePHIDType' => 'PhabricatorPHIDType',
|
||||
|
@ -4536,6 +4542,7 @@ phutil_register_library_map(array(
|
|||
),
|
||||
'DrydockResourceCloseController' => 'DrydockResourceController',
|
||||
'DrydockResourceController' => 'DrydockController',
|
||||
'DrydockResourceDatasource' => 'PhabricatorTypeaheadDatasource',
|
||||
'DrydockResourceListController' => 'DrydockResourceController',
|
||||
'DrydockResourceListView' => 'AphrontView',
|
||||
'DrydockResourcePHIDType' => 'PhabricatorPHIDType',
|
||||
|
@ -5049,6 +5056,7 @@ phutil_register_library_map(array(
|
|||
'MultimeterSampleController' => 'MultimeterController',
|
||||
'MultimeterViewer' => 'MultimeterDimension',
|
||||
'NuanceConduitAPIMethod' => 'ConduitAPIMethod',
|
||||
'NuanceConsoleController' => 'NuanceController',
|
||||
'NuanceController' => 'PhabricatorController',
|
||||
'NuanceCreateItemConduitAPIMethod' => 'NuanceConduitAPIMethod',
|
||||
'NuanceDAO' => 'PhabricatorLiskDAO',
|
||||
|
@ -5072,9 +5080,9 @@ phutil_register_library_map(array(
|
|||
'PhabricatorPolicyInterface',
|
||||
'PhabricatorApplicationTransactionInterface',
|
||||
),
|
||||
'NuanceQueueDatasource' => 'PhabricatorTypeaheadDatasource',
|
||||
'NuanceQueueEditController' => 'NuanceController',
|
||||
'NuanceQueueEditor' => 'PhabricatorApplicationTransactionEditor',
|
||||
'NuanceQueueItem' => 'NuanceDAO',
|
||||
'NuanceQueueListController' => 'NuanceController',
|
||||
'NuanceQueuePHIDType' => 'PhabricatorPHIDType',
|
||||
'NuanceQueueQuery' => 'NuanceQuery',
|
||||
|
|
|
@ -949,6 +949,12 @@ final class PhabricatorAuditEditor
|
|||
);
|
||||
}
|
||||
|
||||
protected function getCustomWorkerStateEncoding() {
|
||||
return array(
|
||||
'rawPatch' => self::STORAGE_ENCODING_BINARY,
|
||||
);
|
||||
}
|
||||
|
||||
protected function loadCustomWorkerState(array $state) {
|
||||
$this->rawPatch = idx($state, 'rawPatch');
|
||||
$this->affectedFiles = idx($state, 'affectedFiles');
|
||||
|
|
|
@ -37,11 +37,25 @@ final class PhabricatorDashboardTextPanelType
|
|||
PhabricatorDashboardPanelRenderingEngine $engine) {
|
||||
|
||||
$text = $panel->getProperty('text', '');
|
||||
$oneoff = id(new PhabricatorMarkupOneOff())->setContent($text);
|
||||
$field = 'default';
|
||||
|
||||
$text_content = PhabricatorMarkupEngine::renderOneObject(
|
||||
id(new PhabricatorMarkupOneOff())->setContent($text),
|
||||
'default',
|
||||
$viewer);
|
||||
// NOTE: We're taking extra steps here to prevent creation of a text panel
|
||||
// which embeds itself using `{Wnnn}`, recursing indefinitely.
|
||||
|
||||
$parent_key = PhabricatorDashboardRemarkupRule::KEY_PARENT_PANEL_PHIDS;
|
||||
$parent_phids = $engine->getParentPanelPHIDs();
|
||||
$parent_phids[] = $panel->getPHID();
|
||||
|
||||
$markup_engine = id(new PhabricatorMarkupEngine())
|
||||
->setViewer($viewer)
|
||||
->setContextObject($panel)
|
||||
->setAuxiliaryConfig($parent_key, $parent_phids);
|
||||
|
||||
$text_content = $markup_engine
|
||||
->addObject($oneoff, $field)
|
||||
->process()
|
||||
->getOutput($oneoff, $field);
|
||||
|
||||
return id(new PHUIPropertyListView())
|
||||
->addTextContent($text_content);
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
final class PhabricatorDashboardRemarkupRule
|
||||
extends PhabricatorObjectRemarkupRule {
|
||||
|
||||
const KEY_PARENT_PANEL_PHIDS = 'dashboard.parentPanelPHIDs';
|
||||
|
||||
protected function getObjectNamePrefix() {
|
||||
return 'W';
|
||||
}
|
||||
|
@ -21,12 +23,16 @@ final class PhabricatorDashboardRemarkupRule
|
|||
PhabricatorObjectHandle $handle,
|
||||
$options) {
|
||||
|
||||
$viewer = $this->getEngine()->getConfig('viewer');
|
||||
$engine = $this->getEngine();
|
||||
$viewer = $engine->getConfig('viewer');
|
||||
|
||||
$parent_key = self::KEY_PARENT_PANEL_PHIDS;
|
||||
$parent_phids = $engine->getConfig($parent_key, array());
|
||||
|
||||
return id(new PhabricatorDashboardPanelRenderingEngine())
|
||||
->setViewer($viewer)
|
||||
->setPanel($object)
|
||||
->setParentPanelPHIDs(array())
|
||||
->setParentPanelPHIDs($parent_phids)
|
||||
->renderPanel();
|
||||
|
||||
}
|
||||
|
|
|
@ -76,6 +76,9 @@ final class DifferentialCustomFieldRevertsParserTestCase
|
|||
),
|
||||
),
|
||||
|
||||
// This tests a degenerate regex behavior, see T9268.
|
||||
'Reverts aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaz' => array(),
|
||||
|
||||
"This doesn't revert anything" => array(),
|
||||
'nonrevert of r11' => array(),
|
||||
'fixed a bug' => array(),
|
||||
|
|
|
@ -29,6 +29,9 @@ final class DrydockLeasePHIDType extends PhabricatorPHIDType {
|
|||
$lease = $objects[$phid];
|
||||
$id = $lease->getID();
|
||||
|
||||
$handle->setName(pht(
|
||||
'Lease %d',
|
||||
$id));
|
||||
$handle->setURI("/drydock/lease/{$id}/");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ final class DrydockResourcePHIDType extends PhabricatorPHIDType {
|
|||
$resource = $objects[$phid];
|
||||
$id = $resource->getID();
|
||||
|
||||
$handle->setName($resource->getName());
|
||||
$handle->setURI("/drydock/resource/{$id}/");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ final class DrydockBlueprintQuery extends DrydockQuery {
|
|||
|
||||
private $ids;
|
||||
private $phids;
|
||||
private $datasourceQuery;
|
||||
|
||||
public function withIDs(array $ids) {
|
||||
$this->ids = $ids;
|
||||
|
@ -15,6 +16,11 @@ final class DrydockBlueprintQuery extends DrydockQuery {
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function withDatasourceQuery($query) {
|
||||
$this->datasourceQuery = $query;
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function loadPage() {
|
||||
$table = new DrydockBlueprint();
|
||||
$conn_r = $table->establishConnection('r');
|
||||
|
@ -45,20 +51,27 @@ final class DrydockBlueprintQuery extends DrydockQuery {
|
|||
protected function buildWhereClause(AphrontDatabaseConnection $conn_r) {
|
||||
$where = array();
|
||||
|
||||
if ($this->ids) {
|
||||
if ($this->ids !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
'id IN (%Ld)',
|
||||
$this->ids);
|
||||
}
|
||||
|
||||
if ($this->phids) {
|
||||
if ($this->phids !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
'phid IN (%Ls)',
|
||||
$this->phids);
|
||||
}
|
||||
|
||||
if ($this->datasourceQuery !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
'blueprintName LIKE %>',
|
||||
$this->datasourceQuery);
|
||||
}
|
||||
|
||||
return $this->formatWhereClause($where);
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ final class DrydockLeaseQuery extends DrydockQuery {
|
|||
private $phids;
|
||||
private $resourceIDs;
|
||||
private $statuses;
|
||||
private $datasourceQuery;
|
||||
|
||||
public function withIDs(array $ids) {
|
||||
$this->ids = $ids;
|
||||
|
@ -31,6 +32,11 @@ final class DrydockLeaseQuery extends DrydockQuery {
|
|||
return new DrydockLease();
|
||||
}
|
||||
|
||||
public function withDatasourceQuery($query) {
|
||||
$this->datasourceQuery = $query;
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function loadPage() {
|
||||
return $this->loadStandardPage($this->newResultObject());
|
||||
}
|
||||
|
@ -41,7 +47,7 @@ final class DrydockLeaseQuery extends DrydockQuery {
|
|||
$resources = id(new DrydockResourceQuery())
|
||||
->setParentQuery($this)
|
||||
->setViewer($this->getViewer())
|
||||
->withIDs($resource_ids)
|
||||
->withIDs(array_unique($resource_ids))
|
||||
->execute();
|
||||
} else {
|
||||
$resources = array();
|
||||
|
@ -93,6 +99,13 @@ final class DrydockLeaseQuery extends DrydockQuery {
|
|||
$this->statuses);
|
||||
}
|
||||
|
||||
if ($this->datasourceQuery !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'id = %d',
|
||||
(int)$this->datasourceQuery);
|
||||
}
|
||||
|
||||
return $where;
|
||||
}
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ final class DrydockLogQuery extends DrydockQuery {
|
|||
$resources = id(new DrydockResourceQuery())
|
||||
->setParentQuery($this)
|
||||
->setViewer($this->getViewer())
|
||||
->withIDs($resource_ids)
|
||||
->withIDs(array_unique($resource_ids))
|
||||
->execute();
|
||||
} else {
|
||||
$resources = array();
|
||||
|
@ -59,7 +59,7 @@ final class DrydockLogQuery extends DrydockQuery {
|
|||
$leases = id(new DrydockLeaseQuery())
|
||||
->setParentQuery($this)
|
||||
->setViewer($this->getViewer())
|
||||
->withIDs($lease_ids)
|
||||
->withIDs(array_unique($lease_ids))
|
||||
->execute();
|
||||
} else {
|
||||
$leases = array();
|
||||
|
@ -91,14 +91,14 @@ final class DrydockLogQuery extends DrydockQuery {
|
|||
protected function buildWhereClause(AphrontDatabaseConnection $conn_r) {
|
||||
$where = array();
|
||||
|
||||
if ($this->resourceIDs) {
|
||||
if ($this->resourceIDs !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
'resourceID IN (%Ld)',
|
||||
$this->resourceIDs);
|
||||
}
|
||||
|
||||
if ($this->leaseIDs) {
|
||||
if ($this->leaseIDs !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
'leaseID IN (%Ld)',
|
||||
|
|
|
@ -11,16 +11,71 @@ final class DrydockLogSearchEngine extends PhabricatorApplicationSearchEngine {
|
|||
}
|
||||
|
||||
public function buildSavedQueryFromRequest(AphrontRequest $request) {
|
||||
return new PhabricatorSavedQuery();
|
||||
$query = new PhabricatorSavedQuery();
|
||||
|
||||
$query->setParameter(
|
||||
'resourcePHIDs',
|
||||
$this->readListFromRequest($request, 'resources'));
|
||||
$query->setParameter(
|
||||
'leasePHIDs',
|
||||
$this->readListFromRequest($request, 'leases'));
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) {
|
||||
return new DrydockLogQuery();
|
||||
$resource_phids = $saved->getParameter('resourcePHIDs', array());
|
||||
$lease_phids = $saved->getParameter('leasePHIDs', array());
|
||||
|
||||
// TODO: Change logs to use PHIDs instead of IDs.
|
||||
$resource_ids = array();
|
||||
$lease_ids = array();
|
||||
|
||||
if ($resource_phids) {
|
||||
$resource_ids = id(new DrydockResourceQuery())
|
||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||
->withPHIDs($resource_phids)
|
||||
->execute();
|
||||
$resource_ids = mpull($resource_ids, 'getID');
|
||||
}
|
||||
|
||||
if ($lease_phids) {
|
||||
$lease_ids = id(new DrydockLeaseQuery())
|
||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||
->withPHIDs($lease_phids)
|
||||
->execute();
|
||||
$lease_ids = mpull($lease_ids, 'getID');
|
||||
}
|
||||
|
||||
$query = new DrydockLogQuery();
|
||||
if ($resource_ids) {
|
||||
$query->withResourceIDs($resource_ids);
|
||||
}
|
||||
if ($lease_ids) {
|
||||
$query->withLeaseIDs($lease_ids);
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
public function buildSearchForm(
|
||||
AphrontFormView $form,
|
||||
PhabricatorSavedQuery $saved) {}
|
||||
PhabricatorSavedQuery $saved) {
|
||||
|
||||
$form
|
||||
->appendControl(
|
||||
id(new AphrontFormTokenizerControl())
|
||||
->setDatasource(new DrydockResourceDatasource())
|
||||
->setName('resources')
|
||||
->setLabel(pht('Resources'))
|
||||
->setValue($saved->getParameter('resourcePHIDs', array())))
|
||||
->appendControl(
|
||||
id(new AphrontFormTokenizerControl())
|
||||
->setDatasource(new DrydockLeaseDatasource())
|
||||
->setName('leases')
|
||||
->setLabel(pht('Leases'))
|
||||
->setValue($saved->getParameter('leasePHIDs', array())));
|
||||
}
|
||||
|
||||
protected function getURI($path) {
|
||||
return '/drydock/log/'.$path;
|
||||
|
|
|
@ -7,6 +7,7 @@ final class DrydockResourceQuery extends DrydockQuery {
|
|||
private $statuses;
|
||||
private $types;
|
||||
private $blueprintPHIDs;
|
||||
private $datasourceQuery;
|
||||
|
||||
public function withIDs(array $ids) {
|
||||
$this->ids = $ids;
|
||||
|
@ -33,6 +34,11 @@ final class DrydockResourceQuery extends DrydockQuery {
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function withDatasourceQuery($query) {
|
||||
$this->datasourceQuery = $query;
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function loadPage() {
|
||||
$table = new DrydockResource();
|
||||
$conn_r = $table->establishConnection('r');
|
||||
|
@ -53,41 +59,48 @@ final class DrydockResourceQuery extends DrydockQuery {
|
|||
protected function buildWhereClause(AphrontDatabaseConnection $conn_r) {
|
||||
$where = array();
|
||||
|
||||
if ($this->ids) {
|
||||
if ($this->ids !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
'id IN (%Ld)',
|
||||
$this->ids);
|
||||
}
|
||||
|
||||
if ($this->phids) {
|
||||
if ($this->phids !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
'phid IN (%Ls)',
|
||||
$this->phids);
|
||||
}
|
||||
|
||||
if ($this->types) {
|
||||
if ($this->types !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
'type IN (%Ls)',
|
||||
$this->types);
|
||||
}
|
||||
|
||||
if ($this->statuses) {
|
||||
if ($this->statuses !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
'status IN (%Ls)',
|
||||
$this->statuses);
|
||||
}
|
||||
|
||||
if ($this->blueprintPHIDs) {
|
||||
if ($this->blueprintPHIDs !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
'blueprintPHID IN (%Ls)',
|
||||
$this->blueprintPHIDs);
|
||||
}
|
||||
|
||||
if ($this->datasourceQuery !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
'name LIKE %>',
|
||||
$this->datasourceQuery);
|
||||
}
|
||||
|
||||
$where[] = $this->buildPagingClause($conn_r);
|
||||
|
||||
return $this->formatWhereClause($where);
|
||||
|
|
|
@ -40,7 +40,7 @@ final class DrydockBlueprint extends DrydockDAO
|
|||
),
|
||||
self::CONFIG_COLUMN_SCHEMA => array(
|
||||
'className' => 'text255',
|
||||
'blueprintName' => 'text255',
|
||||
'blueprintName' => 'sort255',
|
||||
),
|
||||
) + parent::getConfiguration();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
final class DrydockBlueprintDatasource
|
||||
extends PhabricatorTypeaheadDatasource {
|
||||
|
||||
public function getPlaceholderText() {
|
||||
return pht('Type a blueprint name...');
|
||||
}
|
||||
|
||||
public function getDatasourceApplicationClass() {
|
||||
return 'PhabricatorDrydockApplication';
|
||||
}
|
||||
|
||||
public function loadResults() {
|
||||
$viewer = $this->getViewer();
|
||||
$raw_query = $this->getRawQuery();
|
||||
|
||||
$blueprints = id(new DrydockBlueprintQuery())
|
||||
->setViewer($viewer)
|
||||
->withDatasourceQuery($raw_query)
|
||||
->execute();
|
||||
|
||||
$handles = id(new PhabricatorHandleQuery())
|
||||
->setViewer($viewer)
|
||||
->withPHIDs(mpull($blueprints, 'getPHID'))
|
||||
->execute();
|
||||
|
||||
$results = array();
|
||||
foreach ($handles as $handle) {
|
||||
$results[] = id(new PhabricatorTypeaheadResult())
|
||||
->setName($handle->getName())
|
||||
->setPHID($handle->getPHID());
|
||||
}
|
||||
return $results;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
final class DrydockLeaseDatasource
|
||||
extends PhabricatorTypeaheadDatasource {
|
||||
|
||||
public function getPlaceholderText() {
|
||||
return pht('Type a lease ID (exact match)...');
|
||||
}
|
||||
|
||||
public function getDatasourceApplicationClass() {
|
||||
return 'PhabricatorDrydockApplication';
|
||||
}
|
||||
|
||||
public function loadResults() {
|
||||
$viewer = $this->getViewer();
|
||||
$raw_query = $this->getRawQuery();
|
||||
|
||||
$leases = id(new DrydockLeaseQuery())
|
||||
->setViewer($viewer)
|
||||
->withDatasourceQuery($raw_query)
|
||||
->execute();
|
||||
|
||||
$handles = id(new PhabricatorHandleQuery())
|
||||
->setViewer($viewer)
|
||||
->withPHIDs(mpull($leases, 'getPHID'))
|
||||
->execute();
|
||||
|
||||
$results = array();
|
||||
foreach ($handles as $handle) {
|
||||
$results[] = id(new PhabricatorTypeaheadResult())
|
||||
->setName($handle->getName())
|
||||
->setPHID($handle->getPHID());
|
||||
}
|
||||
return $results;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
final class DrydockResourceDatasource
|
||||
extends PhabricatorTypeaheadDatasource {
|
||||
|
||||
public function getPlaceholderText() {
|
||||
return pht('Type a resource name...');
|
||||
}
|
||||
|
||||
public function getDatasourceApplicationClass() {
|
||||
return 'PhabricatorDrydockApplication';
|
||||
}
|
||||
|
||||
public function loadResults() {
|
||||
$viewer = $this->getViewer();
|
||||
$raw_query = $this->getRawQuery();
|
||||
|
||||
$resources = id(new DrydockResourceQuery())
|
||||
->setViewer($viewer)
|
||||
->withDatasourceQuery($raw_query)
|
||||
->execute();
|
||||
|
||||
$handles = id(new PhabricatorHandleQuery())
|
||||
->setViewer($viewer)
|
||||
->withPHIDs(mpull($resources, 'getPHID'))
|
||||
->execute();
|
||||
|
||||
$results = array();
|
||||
foreach ($handles as $handle) {
|
||||
$results[] = id(new PhabricatorTypeaheadResult())
|
||||
->setName($handle->getName())
|
||||
->setPHID($handle->getPHID());
|
||||
}
|
||||
return $results;
|
||||
}
|
||||
}
|
|
@ -21,13 +21,18 @@ final class DrydockLogListView extends AphrontView {
|
|||
$resource_uri = '/drydock/resource/'.$log->getResourceID().'/';
|
||||
$lease_uri = '/drydock/lease/'.$log->getLeaseID().'/';
|
||||
|
||||
$resource_name = $log->getResourceID();
|
||||
if ($log->getResourceID() !== null) {
|
||||
$resource_name = $log->getResource()->getName();
|
||||
}
|
||||
|
||||
$rows[] = array(
|
||||
phutil_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => $resource_uri,
|
||||
),
|
||||
$log->getResourceID()),
|
||||
$resource_name),
|
||||
phutil_tag(
|
||||
'a',
|
||||
array(
|
||||
|
@ -35,7 +40,7 @@ final class DrydockLogListView extends AphrontView {
|
|||
),
|
||||
$log->getLeaseID()),
|
||||
$log->getMessage(),
|
||||
phabricator_date($log->getEpoch(), $viewer),
|
||||
phabricator_datetime($log->getEpoch(), $viewer),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ final class HarbormasterLeaseHostBuildStepImplementation
|
|||
// Create the lease.
|
||||
$lease = id(new DrydockLease())
|
||||
->setResourceType('host')
|
||||
->setOwnerPHID($build_target->getPHID())
|
||||
->setAttributes(
|
||||
array(
|
||||
'platform' => $settings['platform'],
|
||||
|
|
|
@ -234,11 +234,19 @@ final class LegalpadDocumentSignController extends LegalpadController {
|
|||
$document,
|
||||
PhabricatorPolicyCapability::CAN_EDIT);
|
||||
|
||||
// Use the last content update as the modified date. We don't want to
|
||||
// show that a document like a TOS was "updated" by an incidental change
|
||||
// to a field like the preamble or privacy settings which does not acutally
|
||||
// affect the content of the agreement.
|
||||
$content_updated = $document_body->getDateCreated();
|
||||
|
||||
// NOTE: We're avoiding `setPolicyObject()` here so we don't pick up
|
||||
// extra UI elements that are unnecessary and clutter the signature page.
|
||||
// These details are available on the "Manage" page.
|
||||
$header = id(new PHUIHeaderView())
|
||||
->setHeader($title)
|
||||
->setUser($viewer)
|
||||
->setPolicyObject($document)
|
||||
->setEpoch($document->getDateModified())
|
||||
->setEpoch($content_updated)
|
||||
->addActionLink(
|
||||
id(new PHUIButtonView())
|
||||
->setTag('a')
|
||||
|
@ -258,15 +266,16 @@ final class LegalpadDocumentSignController extends LegalpadController {
|
|||
'default',
|
||||
$viewer);
|
||||
|
||||
// NOTE: We're avoiding `setObject()` here so we don't pick up extra UI
|
||||
// elements like "Subscribers". This information is available on the
|
||||
// "Manage" page, but just clutters up the "Signature" page.
|
||||
$preamble = id(new PHUIPropertyListView())
|
||||
->setUser($viewer)
|
||||
->setObject($document)
|
||||
->addSectionHeader(pht('Preamble'))
|
||||
->addTextContent($preamble_text);
|
||||
|
||||
$preamble_box = new PHUIPropertyGroupView();
|
||||
$preamble_box->addPropertyList($preamble);
|
||||
|
||||
}
|
||||
|
||||
$content = id(new PHUIDocumentView())
|
||||
|
|
|
@ -7,11 +7,18 @@ final class PhabricatorMailManagementVolumeWorkflow
|
|||
$this
|
||||
->setName('volume')
|
||||
->setSynopsis(
|
||||
pht('Show how much mail users have received in the last 30 days.'))
|
||||
pht('Show how much mail users have received recently.'))
|
||||
->setExamples(
|
||||
'**volume**')
|
||||
->setArguments(
|
||||
array(
|
||||
array(
|
||||
'name' => 'days',
|
||||
'param' => 'days',
|
||||
'default' => 30,
|
||||
'help' => pht(
|
||||
'Number of days back (default 30).'),
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -19,7 +26,16 @@ final class PhabricatorMailManagementVolumeWorkflow
|
|||
$console = PhutilConsole::getConsole();
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$since = (PhabricatorTime::getNow() - phutil_units('30 days in seconds'));
|
||||
$days = (int)$args->getArg('days');
|
||||
if ($days < 1) {
|
||||
throw new PhutilArgumentUsageException(
|
||||
pht(
|
||||
'Period specified with --days must be at least 1.'));
|
||||
}
|
||||
|
||||
$duration = phutil_units("{$days} days in seconds");
|
||||
|
||||
$since = (PhabricatorTime::getNow() - $duration);
|
||||
$until = PhabricatorTime::getNow();
|
||||
|
||||
$mails = id(new PhabricatorMetaMTAMailQuery())
|
||||
|
@ -95,7 +111,9 @@ final class PhabricatorMailManagementVolumeWorkflow
|
|||
$table->draw();
|
||||
|
||||
echo "\n";
|
||||
echo pht('Mail sent in the last 30 days.')."\n";
|
||||
echo pht(
|
||||
'Mail sent in the last %s day(s).',
|
||||
new PhutilNumber($days))."\n";
|
||||
echo pht(
|
||||
'"Unfiltered" is raw volume before rules applied.')."\n";
|
||||
echo pht(
|
||||
|
|
|
@ -10,7 +10,7 @@ final class PhabricatorMetaMTAMail
|
|||
const RETRY_DELAY = 5;
|
||||
|
||||
protected $actorPHID;
|
||||
protected $parameters;
|
||||
protected $parameters = array();
|
||||
protected $status;
|
||||
protected $message;
|
||||
protected $relatedPHID;
|
||||
|
@ -69,6 +69,13 @@ final class PhabricatorMetaMTAMail
|
|||
}
|
||||
|
||||
protected function getParam($param, $default = null) {
|
||||
// Some old mail was saved without parameters because no parameters were
|
||||
// set or encoding failed. Recover in these cases so we can perform
|
||||
// mail migrations, see T9251.
|
||||
if (!is_array($this->parameters)) {
|
||||
$this->parameters = array();
|
||||
}
|
||||
|
||||
return idx($this->parameters, $param, $default);
|
||||
}
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ final class PhabricatorNuanceApplication extends PhabricatorApplication {
|
|||
public function getRoutes() {
|
||||
return array(
|
||||
'/nuance/' => array(
|
||||
'' => 'NuanceConsoleController',
|
||||
'item/' => array(
|
||||
'view/(?P<id>[1-9]\d*)/' => 'NuanceItemViewController',
|
||||
'edit/(?P<id>[1-9]\d*)/' => 'NuanceItemEditController',
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
final class NuanceConsoleController extends NuanceController {
|
||||
|
||||
public function shouldAllowPublic() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$viewer = $request->getViewer();
|
||||
|
||||
$menu = id(new PHUIObjectItemListView())
|
||||
->setUser($viewer);
|
||||
|
||||
$menu->addItem(
|
||||
id(new PHUIObjectItemView())
|
||||
->setHeader(pht('Queues'))
|
||||
->setHref($this->getApplicationURI('queue/'))
|
||||
->setFontIcon('fa-align-left')
|
||||
->addAttribute(pht('Manage Nuance queues.')));
|
||||
|
||||
$menu->addItem(
|
||||
id(new PHUIObjectItemView())
|
||||
->setHeader(pht('Sources'))
|
||||
->setHref($this->getApplicationURI('source/'))
|
||||
->setFontIcon('fa-filter')
|
||||
->addAttribute(pht('Manage Nuance sources.')));
|
||||
|
||||
$crumbs = $this->buildApplicationCrumbs();
|
||||
$crumbs->addTextCrumb(pht('Console'));
|
||||
|
||||
$box = id(new PHUIObjectBoxView())
|
||||
->setHeaderText(pht('Console'))
|
||||
->setObjectList($menu);
|
||||
|
||||
return $this->buildApplicationPage(
|
||||
array(
|
||||
$crumbs,
|
||||
$box,
|
||||
),
|
||||
array(
|
||||
'title' => pht('Nuance Console'),
|
||||
));
|
||||
}
|
||||
|
||||
}
|
|
@ -3,30 +3,102 @@
|
|||
final class NuanceItemEditController extends NuanceController {
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$viewer = $request->getViewer();
|
||||
$viewer = $this->getViewer();
|
||||
$id = $request->getURIData('id');
|
||||
|
||||
if (!$id) {
|
||||
$item = new NuanceItem();
|
||||
} else {
|
||||
$item = id(new NuanceItemQuery())
|
||||
->setViewer($viewer)
|
||||
->withIDs(array($id))
|
||||
->executeOne();
|
||||
}
|
||||
|
||||
$item = id(new NuanceItemQuery())
|
||||
->setViewer($viewer)
|
||||
->withIDs(array($id))
|
||||
->requireCapabilities(
|
||||
array(
|
||||
PhabricatorPolicyCapability::CAN_VIEW,
|
||||
PhabricatorPolicyCapability::CAN_EDIT,
|
||||
))
|
||||
->executeOne();
|
||||
if (!$item) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$title = pht('Item %d', $item->getID());
|
||||
|
||||
$crumbs = $this->buildApplicationCrumbs();
|
||||
$title = 'TODO';
|
||||
$crumbs->addTextCrumb($title);
|
||||
$crumbs->addTextCrumb(pht('Edit'));
|
||||
|
||||
$properties = $this->buildPropertyView($item);
|
||||
$actions = $this->buildActionView($item);
|
||||
$properties->setActionList($actions);
|
||||
|
||||
$box = id(new PHUIObjectBoxView())
|
||||
->setHeaderText($title)
|
||||
->addPropertyList($properties);
|
||||
|
||||
$timeline = $this->buildTransactionTimeline(
|
||||
$item,
|
||||
new NuanceItemTransactionQuery());
|
||||
|
||||
$timeline->setShouldTerminate(true);
|
||||
|
||||
return $this->buildApplicationPage(
|
||||
$crumbs,
|
||||
array(
|
||||
$crumbs,
|
||||
$box,
|
||||
$timeline,
|
||||
),
|
||||
array(
|
||||
'title' => $title,
|
||||
));
|
||||
}
|
||||
|
||||
private function buildPropertyView(NuanceItem $item) {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$properties = id(new PHUIPropertyListView())
|
||||
->setUser($viewer)
|
||||
->setObject($item);
|
||||
|
||||
$properties->addProperty(
|
||||
pht('Date Created'),
|
||||
phabricator_datetime($item->getDateCreated(), $viewer));
|
||||
|
||||
$properties->addProperty(
|
||||
pht('Requestor'),
|
||||
$viewer->renderHandle($item->getRequestorPHID()));
|
||||
|
||||
$properties->addProperty(
|
||||
pht('Source'),
|
||||
$viewer->renderHandle($item->getSourcePHID()));
|
||||
|
||||
$properties->addProperty(
|
||||
pht('Queue'),
|
||||
$viewer->renderHandle($item->getQueuePHID()));
|
||||
|
||||
$source = $item->getSource();
|
||||
$definition = $source->requireDefinition();
|
||||
|
||||
$definition->renderItemEditProperties(
|
||||
$viewer,
|
||||
$item,
|
||||
$properties);
|
||||
|
||||
return $properties;
|
||||
}
|
||||
|
||||
private function buildActionView(NuanceItem $item) {
|
||||
$viewer = $this->getViewer();
|
||||
$id = $item->getID();
|
||||
|
||||
$actions = id(new PhabricatorActionListView())
|
||||
->setUser($viewer);
|
||||
|
||||
$actions->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setName(pht('View Item'))
|
||||
->setIcon('fa-eye')
|
||||
->setHref($this->getApplicationURI("item/view/{$id}/")));
|
||||
|
||||
return $actions;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -3,25 +3,84 @@
|
|||
final class NuanceItemViewController extends NuanceController {
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$viewer = $request->getViewer();
|
||||
$viewer = $this->getViewer();
|
||||
$id = $request->getURIData('id');
|
||||
|
||||
$item = id(new NuanceItemQuery())
|
||||
->setViewer($viewer)
|
||||
->withIDs(array($id))
|
||||
->executeOne();
|
||||
|
||||
if (!$item) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$title = pht('Item %d', $item->getID());
|
||||
|
||||
$crumbs = $this->buildApplicationCrumbs();
|
||||
$title = 'TODO';
|
||||
$crumbs->addTextCrumb($title);
|
||||
|
||||
$properties = $this->buildPropertyView($item);
|
||||
$actions = $this->buildActionView($item);
|
||||
$properties->setActionList($actions);
|
||||
|
||||
$box = id(new PHUIObjectBoxView())
|
||||
->setHeaderText($title)
|
||||
->addPropertyList($properties);
|
||||
|
||||
return $this->buildApplicationPage(
|
||||
$crumbs,
|
||||
array(
|
||||
$crumbs,
|
||||
$box,
|
||||
),
|
||||
array(
|
||||
'title' => $title,
|
||||
));
|
||||
}
|
||||
|
||||
private function buildPropertyView(NuanceItem $item) {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$properties = id(new PHUIPropertyListView())
|
||||
->setUser($viewer)
|
||||
->setObject($item);
|
||||
|
||||
$properties->addProperty(
|
||||
pht('Date Created'),
|
||||
phabricator_datetime($item->getDateCreated(), $viewer));
|
||||
|
||||
$source = $item->getSource();
|
||||
$definition = $source->requireDefinition();
|
||||
|
||||
$definition->renderItemViewProperties(
|
||||
$viewer,
|
||||
$item,
|
||||
$properties);
|
||||
|
||||
return $properties;
|
||||
}
|
||||
|
||||
private function buildActionView(NuanceItem $item) {
|
||||
$viewer = $this->getViewer();
|
||||
$id = $item->getID();
|
||||
|
||||
$actions = id(new PhabricatorActionListView())
|
||||
->setUser($viewer);
|
||||
|
||||
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
||||
$viewer,
|
||||
$item,
|
||||
PhabricatorPolicyCapability::CAN_EDIT);
|
||||
|
||||
$actions->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setName(pht('Edit Item'))
|
||||
->setIcon('fa-pencil')
|
||||
->setHref($this->getApplicationURI("item/edit/{$id}/"))
|
||||
->setDisabled(!$can_edit)
|
||||
->setWorkflow(!$can_edit));
|
||||
|
||||
return $actions;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ final class NuanceSourceActionController extends NuanceController {
|
|||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$def = NuanceSourceDefinition::getDefinitionForSource($source);
|
||||
$def = $source->requireDefinition();
|
||||
$def->setActor($viewer);
|
||||
|
||||
$response = $def->handleActionRequest($request);
|
||||
|
|
|
@ -41,7 +41,7 @@ final class NuanceSourceEditController extends NuanceController {
|
|||
$cancel_uri = $source->getURI();
|
||||
}
|
||||
|
||||
$definition = NuanceSourceDefinition::getDefinitionForSource($source);
|
||||
$definition = $source->requireDefinition();
|
||||
$definition->setActor($viewer);
|
||||
|
||||
$response = $definition->buildEditLayout($request);
|
||||
|
|
|
@ -13,7 +13,7 @@ final class NuanceSourceViewController extends NuanceController {
|
|||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$source_phid = $source->getPHID();
|
||||
$source_id = $source->getID();
|
||||
|
||||
$timeline = $this->buildTransactionTimeline(
|
||||
$source,
|
||||
|
@ -34,10 +34,29 @@ final class NuanceSourceViewController extends NuanceController {
|
|||
|
||||
$crumbs->addTextCrumb($title);
|
||||
|
||||
|
||||
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
||||
$viewer,
|
||||
$source,
|
||||
PhabricatorPolicyCapability::CAN_EDIT);
|
||||
|
||||
$routing_list = id(new PHUIPropertyListView())
|
||||
->addProperty(
|
||||
pht('Default Queue'),
|
||||
$viewer->renderHandle($source->getDefaultQueuePHID()));
|
||||
|
||||
$routing_header = id(new PHUIHeaderView())
|
||||
->setHeader(pht('Routing Rules'));
|
||||
|
||||
$routing = id(new PHUIObjectBoxView())
|
||||
->setHeader($routing_header)
|
||||
->addPropertyList($routing_list);
|
||||
|
||||
return $this->buildApplicationPage(
|
||||
array(
|
||||
$crumbs,
|
||||
$box,
|
||||
$routing,
|
||||
$timeline,
|
||||
),
|
||||
array(
|
||||
|
@ -77,6 +96,13 @@ final class NuanceSourceViewController extends NuanceController {
|
|||
->setDisabled(!$can_edit)
|
||||
->setWorkflow(!$can_edit));
|
||||
|
||||
$request = $this->getRequest();
|
||||
$definition = $source->requireDefinition();
|
||||
$source_actions = $definition->getSourceViewActions($request);
|
||||
foreach ($source_actions as $source_action) {
|
||||
$actions->addAction($source_action);
|
||||
}
|
||||
|
||||
return $actions;
|
||||
}
|
||||
|
||||
|
@ -90,7 +116,7 @@ final class NuanceSourceViewController extends NuanceController {
|
|||
->setObject($source)
|
||||
->setActionList($actions);
|
||||
|
||||
$definition = NuanceSourceDefinition::getDefinitionForSource($source);
|
||||
$definition = $source->requireDefinition();
|
||||
$properties->addProperty(
|
||||
pht('Source Type'),
|
||||
$definition->getName());
|
||||
|
|
|
@ -18,6 +18,7 @@ final class NuanceItemEditor
|
|||
$types[] = NuanceItemTransaction::TYPE_SOURCE;
|
||||
$types[] = NuanceItemTransaction::TYPE_REQUESTOR;
|
||||
$types[] = NuanceItemTransaction::TYPE_PROPERTY;
|
||||
$types[] = NuanceItemTransaction::TYPE_QUEUE;
|
||||
|
||||
$types[] = PhabricatorTransactions::TYPE_EDGE;
|
||||
$types[] = PhabricatorTransactions::TYPE_COMMENT;
|
||||
|
@ -38,6 +39,8 @@ final class NuanceItemEditor
|
|||
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);
|
||||
|
@ -56,6 +59,7 @@ final class NuanceItemEditor
|
|||
case NuanceItemTransaction::TYPE_SOURCE:
|
||||
case NuanceItemTransaction::TYPE_OWNER:
|
||||
case NuanceItemTransaction::TYPE_PROPERTY:
|
||||
case NuanceItemTransaction::TYPE_QUEUE:
|
||||
return $xaction->getNewValue();
|
||||
}
|
||||
|
||||
|
@ -76,6 +80,9 @@ final class NuanceItemEditor
|
|||
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);
|
||||
|
@ -93,6 +100,7 @@ final class NuanceItemEditor
|
|||
case NuanceItemTransaction::TYPE_SOURCE:
|
||||
case NuanceItemTransaction::TYPE_OWNER:
|
||||
case NuanceItemTransaction::TYPE_PROPERTY:
|
||||
case NuanceItemTransaction::TYPE_QUEUE:
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ final class NuanceSourceEditor
|
|||
$types = parent::getTransactionTypes();
|
||||
|
||||
$types[] = NuanceSourceTransaction::TYPE_NAME;
|
||||
$types[] = NuanceSourceTransaction::TYPE_DEFAULT_QUEUE;
|
||||
|
||||
$types[] = PhabricatorTransactions::TYPE_EDGE;
|
||||
$types[] = PhabricatorTransactions::TYPE_COMMENT;
|
||||
|
@ -31,6 +32,8 @@ final class NuanceSourceEditor
|
|||
switch ($xaction->getTransactionType()) {
|
||||
case NuanceSourceTransaction::TYPE_NAME:
|
||||
return $object->getName();
|
||||
case NuanceSourceTransaction::TYPE_DEFAULT_QUEUE:
|
||||
return $object->getDefaultQueuePHID();
|
||||
}
|
||||
|
||||
return parent::getCustomTransactionOldValue($object, $xaction);
|
||||
|
@ -42,6 +45,7 @@ final class NuanceSourceEditor
|
|||
|
||||
switch ($xaction->getTransactionType()) {
|
||||
case NuanceSourceTransaction::TYPE_NAME:
|
||||
case NuanceSourceTransaction::TYPE_DEFAULT_QUEUE:
|
||||
return $xaction->getNewValue();
|
||||
}
|
||||
|
||||
|
@ -56,6 +60,9 @@ final class NuanceSourceEditor
|
|||
case NuanceSourceTransaction::TYPE_NAME:
|
||||
$object->setName($xaction->getNewValue());
|
||||
break;
|
||||
case NuanceSourceTransaction::TYPE_DEFAULT_QUEUE:
|
||||
$object->setDefaultQueuePHID($xaction->getNewValue());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -65,6 +72,7 @@ final class NuanceSourceEditor
|
|||
|
||||
switch ($xaction->getTransactionType()) {
|
||||
case NuanceSourceTransaction::TYPE_NAME:
|
||||
case NuanceSourceTransaction::TYPE_DEFAULT_QUEUE:
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -95,6 +103,19 @@ final class NuanceSourceEditor
|
|||
$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;
|
||||
|
|
|
@ -29,7 +29,9 @@ final class NuanceRequestorPHIDType extends PhabricatorPHIDType {
|
|||
foreach ($handles as $phid => $handle) {
|
||||
$requestor = $objects[$phid];
|
||||
|
||||
$handle->setName($requestor->getBestName());
|
||||
// TODO: This is currently useless and should be far more informative.
|
||||
$handle->setName(pht('Requestor %d', $requestor->getID()));
|
||||
|
||||
$handle->setURI($requestor->getURI());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,25 +17,42 @@ final class NuanceItemQuery
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function withSourcePHIDs($source_phids) {
|
||||
public function withSourcePHIDs(array $source_phids) {
|
||||
$this->sourcePHIDs = $source_phids;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function newResultObject() {
|
||||
return new NuanceItem();
|
||||
}
|
||||
|
||||
protected function loadPage() {
|
||||
$table = new NuanceItem();
|
||||
$conn = $table->establishConnection('r');
|
||||
return $this->loadStandardPage($this->newResultObject());
|
||||
}
|
||||
|
||||
$data = queryfx_all(
|
||||
$conn,
|
||||
'%Q FROM %T %Q %Q %Q',
|
||||
$this->buildSelectClause($conn),
|
||||
$table->getTableName(),
|
||||
$this->buildWhereClause($conn),
|
||||
$this->buildOrderClause($conn),
|
||||
$this->buildLimitClause($conn));
|
||||
protected function willFilterPage(array $items) {
|
||||
$source_phids = mpull($items, 'getSourcePHID');
|
||||
|
||||
return $table->loadAllFromArray($data);
|
||||
// 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())
|
||||
->withPHIDs($source_phids)
|
||||
->execute();
|
||||
$sources = mpull($sources, null, 'getPHID');
|
||||
|
||||
foreach ($items as $key => $item) {
|
||||
$source = idx($sources, $item->getSourcePHID());
|
||||
if (!$source) {
|
||||
$this->didRejectResult($items[$key]);
|
||||
unset($items[$key]);
|
||||
continue;
|
||||
}
|
||||
$item->attachSource($source);
|
||||
}
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
|
||||
|
|
|
@ -15,6 +15,17 @@ final class NuancePhabricatorFormSourceDefinition
|
|||
return 'phabricator-form';
|
||||
}
|
||||
|
||||
public function getSourceViewActions(AphrontRequest $request) {
|
||||
$actions = array();
|
||||
|
||||
$actions[] = id(new PhabricatorActionView())
|
||||
->setName(pht('View Form'))
|
||||
->setIcon('fa-align-justify')
|
||||
->setHref($this->getActionURI());
|
||||
|
||||
return $actions;
|
||||
}
|
||||
|
||||
public function updateItems() {
|
||||
return null;
|
||||
}
|
||||
|
@ -50,7 +61,7 @@ final class NuancePhabricatorFormSourceDefinition
|
|||
|
||||
if ($request->isFormPost()) {
|
||||
$properties = array(
|
||||
'complaint' => (string)$request->getStr('text'),
|
||||
'complaint' => (string)$request->getStr('complaint'),
|
||||
);
|
||||
|
||||
$content_source = PhabricatorContentSource::newFromRequest($request);
|
||||
|
@ -89,4 +100,33 @@ final class NuancePhabricatorFormSourceDefinition
|
|||
return $box;
|
||||
}
|
||||
|
||||
public function renderItemViewProperties(
|
||||
PhabricatorUser $viewer,
|
||||
NuanceItem $item,
|
||||
PHUIPropertyListView $view) {
|
||||
$this->renderItemCommonProperties($viewer, $item, $view);
|
||||
}
|
||||
|
||||
public function renderItemEditProperties(
|
||||
PhabricatorUser $viewer,
|
||||
NuanceItem $item,
|
||||
PHUIPropertyListView $view) {
|
||||
$this->renderItemCommonProperties($viewer, $item, $view);
|
||||
}
|
||||
|
||||
private function renderItemCommonProperties(
|
||||
PhabricatorUser $viewer,
|
||||
NuanceItem $item,
|
||||
PHUIPropertyListView $view) {
|
||||
|
||||
$complaint = $item->getNuanceProperty('complaint');
|
||||
$complaint = PhabricatorMarkupEngine::renderOneObject(
|
||||
id(new PhabricatorMarkupOneOff())->setContent($complaint),
|
||||
'default',
|
||||
$viewer);
|
||||
|
||||
$view->addSectionHeader(pht('Complaint'));
|
||||
$view->addTextContent($complaint);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -43,18 +43,8 @@ abstract class NuanceSourceDefinition extends Phobject {
|
|||
return $source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gives a @{class:NuanceSourceDefinition} object for a given
|
||||
* @{class:NuanceSource}. Note you still need to @{method:setActor}
|
||||
* before the @{class:NuanceSourceDefinition} object will be useful.
|
||||
*/
|
||||
public static function getDefinitionForSource(NuanceSource $source) {
|
||||
$definitions = self::getAllDefinitions();
|
||||
$map = mpull($definitions, null, 'getSourceTypeConstant');
|
||||
$definition = $map[$source->getType()];
|
||||
$definition->setSourceObject($source);
|
||||
|
||||
return $definition;
|
||||
public function getSourceViewActions(AphrontRequest $request) {
|
||||
return array();
|
||||
}
|
||||
|
||||
public static function getAllDefinitions() {
|
||||
|
@ -179,25 +169,39 @@ abstract class NuanceSourceDefinition extends Phobject {
|
|||
|
||||
$form = $this->augmentEditForm($form, $ex);
|
||||
|
||||
$default_phid = $source->getDefaultQueuePHID();
|
||||
if ($default_phid) {
|
||||
$default_queues = array($default_phid);
|
||||
} else {
|
||||
$default_queues = array();
|
||||
}
|
||||
|
||||
$form
|
||||
->appendControl(
|
||||
id(new AphrontFormTokenizerControl())
|
||||
->setLabel(pht('Default Queue'))
|
||||
->setName('defaultQueuePHIDs')
|
||||
->setLimit(1)
|
||||
->setDatasource(new NuanceQueueDatasource())
|
||||
->setValue($default_queues))
|
||||
->appendChild(
|
||||
id(new AphrontFormPolicyControl())
|
||||
->setUser($user)
|
||||
->setCapability(PhabricatorPolicyCapability::CAN_VIEW)
|
||||
->setPolicyObject($source)
|
||||
->setPolicies($policies)
|
||||
->setName('viewPolicy'))
|
||||
->setUser($user)
|
||||
->setCapability(PhabricatorPolicyCapability::CAN_VIEW)
|
||||
->setPolicyObject($source)
|
||||
->setPolicies($policies)
|
||||
->setName('viewPolicy'))
|
||||
->appendChild(
|
||||
id(new AphrontFormPolicyControl())
|
||||
->setUser($user)
|
||||
->setCapability(PhabricatorPolicyCapability::CAN_EDIT)
|
||||
->setPolicyObject($source)
|
||||
->setPolicies($policies)
|
||||
->setName('editPolicy'))
|
||||
->setUser($user)
|
||||
->setCapability(PhabricatorPolicyCapability::CAN_EDIT)
|
||||
->setPolicyObject($source)
|
||||
->setPolicies($policies)
|
||||
->setName('editPolicy'))
|
||||
->appendChild(
|
||||
id(new AphrontFormSubmitControl())
|
||||
->addCancelButton($source->getURI())
|
||||
->setValue(pht('Save')));
|
||||
->addCancelButton($source->getURI())
|
||||
->setValue(pht('Save')));
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
@ -223,13 +227,19 @@ abstract class NuanceSourceDefinition extends Phobject {
|
|||
$transactions[] = id(new NuanceSourceTransaction())
|
||||
->setTransactionType(PhabricatorTransactions::TYPE_EDIT_POLICY)
|
||||
->setNewValue($request->getStr('editPolicy'));
|
||||
|
||||
$transactions[] = id(new NuanceSourceTransaction())
|
||||
->setTransactionType(PhabricatorTransactions::TYPE_VIEW_POLICY)
|
||||
->setNewValue($request->getStr('viewPolicy'));
|
||||
$transactions[] = id(new NuanceSourceTransaction())
|
||||
|
||||
$transactions[] = id(new NuanceSourceTransaction())
|
||||
->setTransactionType(NuanceSourceTransaction::TYPE_NAME)
|
||||
->setNewvalue($request->getStr('name'));
|
||||
|
||||
$transactions[] = id(new NuanceSourceTransaction())
|
||||
->setTransactionType(NuanceSourceTransaction::TYPE_DEFAULT_QUEUE)
|
||||
->setNewvalue(head($request->getArr('defaultQueuePHIDs')));
|
||||
|
||||
return $transactions;
|
||||
}
|
||||
|
||||
|
@ -261,6 +271,12 @@ abstract class NuanceSourceDefinition extends Phobject {
|
|||
->setTransactionType(NuanceItemTransaction::TYPE_REQUESTOR)
|
||||
->setNewValue($requestor->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)
|
||||
->setNewValue($source->getDefaultQueuePHID());
|
||||
|
||||
foreach ($properties as $key => $property) {
|
||||
$xactions[] = id(new NuanceItemTransaction())
|
||||
->setTransactionType(NuanceItemTransaction::TYPE_PROPERTY)
|
||||
|
@ -278,6 +294,20 @@ abstract class NuanceSourceDefinition extends Phobject {
|
|||
return $item;
|
||||
}
|
||||
|
||||
public function renderItemViewProperties(
|
||||
PhabricatorUser $viewer,
|
||||
NuanceItem $item,
|
||||
PHUIPropertyListView $view) {
|
||||
return;
|
||||
}
|
||||
|
||||
public function renderItemEditProperties(
|
||||
PhabricatorUser $viewer,
|
||||
NuanceItem $item,
|
||||
PHUIPropertyListView $view) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* -( Handling Action Requests )------------------------------------------- */
|
||||
|
||||
|
@ -286,4 +316,9 @@ abstract class NuanceSourceDefinition extends Phobject {
|
|||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
public function getActionURI($path = null) {
|
||||
$source_id = $this->getSourceObject()->getID();
|
||||
return '/action/'.$source_id.'/'.ltrim($path, '/');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,11 +17,12 @@ final class NuanceItem
|
|||
protected $sourceLabel;
|
||||
protected $data = array();
|
||||
protected $mailKey;
|
||||
protected $dateNuanced;
|
||||
protected $queuePHID;
|
||||
|
||||
private $source = self::ATTACHABLE;
|
||||
|
||||
public static function initializeNewItem() {
|
||||
return id(new NuanceItem())
|
||||
->setDateNuanced(time())
|
||||
->setStatus(self::STATUS_OPEN);
|
||||
}
|
||||
|
||||
|
@ -36,17 +37,19 @@ final class NuanceItem
|
|||
'sourceLabel' => 'text255?',
|
||||
'status' => 'uint32',
|
||||
'mailKey' => 'bytes20',
|
||||
'dateNuanced' => 'epoch',
|
||||
),
|
||||
self::CONFIG_KEY_SCHEMA => array(
|
||||
'key_source' => array(
|
||||
'columns' => array('sourcePHID', 'status', 'dateNuanced', 'id'),
|
||||
'columns' => array('sourcePHID', 'status'),
|
||||
),
|
||||
'key_owner' => array(
|
||||
'columns' => array('ownerPHID', 'status', 'dateNuanced', 'id'),
|
||||
'columns' => array('ownerPHID', 'status'),
|
||||
),
|
||||
'key_contacter' => array(
|
||||
'columns' => array('requestorPHID', 'status', 'dateNuanced', 'id'),
|
||||
'key_requestor' => array(
|
||||
'columns' => array('requestorPHID', 'status'),
|
||||
),
|
||||
'key_queue' => array(
|
||||
'columns' => array('queuePHID', 'status'),
|
||||
),
|
||||
),
|
||||
) + parent::getConfiguration();
|
||||
|
@ -142,7 +145,6 @@ final class NuanceItem
|
|||
'sourceLabel' => $this->getSourceLabel(),
|
||||
'dateCreated' => $this->getDateCreated(),
|
||||
'dateModified' => $this->getDateModified(),
|
||||
'dateNuanced' => $this->getDateNuanced(),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ final class NuanceItemTransaction
|
|||
const TYPE_REQUESTOR = 'nuance.item.requestor';
|
||||
const TYPE_SOURCE = 'nuance.item.source';
|
||||
const TYPE_PROPERTY = 'nuance.item.property';
|
||||
const TYPE_QUEUE = 'nuance.item.queue';
|
||||
|
||||
public function getApplicationTransactionType() {
|
||||
return NuanceItemPHIDType::TYPECONST;
|
||||
|
@ -18,4 +19,55 @@ 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));
|
||||
}
|
||||
|
||||
return parent::getTitle();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class NuanceQueueItem
|
||||
extends NuanceDAO {
|
||||
|
||||
protected $queuePHID;
|
||||
protected $itemPHID;
|
||||
protected $itemStatus;
|
||||
protected $itemDateNuanced;
|
||||
|
||||
protected function getConfiguration() {
|
||||
return array(
|
||||
self::CONFIG_COLUMN_SCHEMA => array(
|
||||
'itemStatus' => 'uint32',
|
||||
'itemDateNuanced' => 'epoch',
|
||||
),
|
||||
self::CONFIG_KEY_SCHEMA => array(
|
||||
'key_one_per_queue' => array(
|
||||
'columns' => array('itemPHID', 'queuePHID'),
|
||||
'unique' => true,
|
||||
),
|
||||
'key_queue' => array(
|
||||
'columns' => array(
|
||||
'queuePHID',
|
||||
'itemStatus',
|
||||
'itemDateNuanced',
|
||||
'id',
|
||||
),
|
||||
),
|
||||
),
|
||||
) + parent::getConfiguration();
|
||||
}
|
||||
|
||||
}
|
|
@ -12,4 +12,34 @@ final class NuanceQueueTransaction extends NuanceTransaction {
|
|||
return new NuanceQueueTransactionComment();
|
||||
}
|
||||
|
||||
public function shouldHide() {
|
||||
$old = $this->getOldValue();
|
||||
$type = $this->getTransactionType();
|
||||
|
||||
switch ($type) {
|
||||
case self::TYPE_NAME:
|
||||
return ($old === null);
|
||||
}
|
||||
|
||||
return parent::shouldHide();
|
||||
}
|
||||
|
||||
public function getTitle() {
|
||||
$old = $this->getOldValue();
|
||||
$new = $this->getNewValue();
|
||||
$type = $this->getTransactionType();
|
||||
|
||||
$author_phid = $this->getAuthorPHID();
|
||||
|
||||
switch ($type) {
|
||||
case self::TYPE_NAME:
|
||||
return pht(
|
||||
'%s renamed this queue from "%s" to "%s".',
|
||||
$this->renderHandleLink($author_phid),
|
||||
$old,
|
||||
$new);
|
||||
}
|
||||
|
||||
return parent::getTitle();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,9 @@ final class NuanceSource extends NuanceDAO
|
|||
protected $mailKey;
|
||||
protected $viewPolicy;
|
||||
protected $editPolicy;
|
||||
protected $defaultQueuePHID;
|
||||
|
||||
private $definition;
|
||||
|
||||
protected function getConfiguration() {
|
||||
return array(
|
||||
|
@ -62,6 +65,31 @@ final class NuanceSource extends NuanceDAO
|
|||
->setEditPolicy($edit_policy);
|
||||
}
|
||||
|
||||
public function getDefinition() {
|
||||
if ($this->definition === null) {
|
||||
$definitions = NuanceSourceDefinition::getAllDefinitions();
|
||||
if (isset($definitions[$this->getType()])) {
|
||||
$definition = clone $definitions[$this->getType()];
|
||||
$definition->setSourceObject($this);
|
||||
$this->definition = $definition;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->definition;
|
||||
}
|
||||
|
||||
public function requireDefinition() {
|
||||
$definition = $this->getDefinition();
|
||||
if (!$definition) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Unable to load source definition implementation for source '.
|
||||
'type "%s".',
|
||||
$this->getType()));
|
||||
}
|
||||
return $definition;
|
||||
}
|
||||
|
||||
|
||||
/* -( PhabricatorApplicationTransactionInterface )------------------------- */
|
||||
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
final class NuanceSourceTransaction
|
||||
extends NuanceTransaction {
|
||||
|
||||
const TYPE_NAME = 'name-source';
|
||||
const TYPE_NAME = 'source.name';
|
||||
const TYPE_DEFAULT_QUEUE = 'source.queue.default';
|
||||
|
||||
public function getApplicationTransactionType() {
|
||||
return NuanceSourcePHIDType::TYPECONST;
|
||||
|
@ -13,27 +14,63 @@ final class NuanceSourceTransaction
|
|||
return new NuanceSourceTransactionComment();
|
||||
}
|
||||
|
||||
public function getTitle() {
|
||||
public function shouldHide() {
|
||||
$old = $this->getOldValue();
|
||||
$new = $this->getNewValue();
|
||||
$author_phid = $this->getAuthorPHID();
|
||||
$type = $this->getTransactionType();
|
||||
|
||||
switch ($this->getTransactionType()) {
|
||||
switch ($type) {
|
||||
case self::TYPE_DEFAULT_QUEUE:
|
||||
return !$old;
|
||||
case self::TYPE_NAME:
|
||||
if ($old === null) {
|
||||
return pht(
|
||||
'%s created this source.',
|
||||
$this->renderHandleLink($author_phid));
|
||||
} else {
|
||||
return pht(
|
||||
'%s renamed this source from "%s" to "%s".',
|
||||
$this->renderHandleLink($author_phid),
|
||||
$old,
|
||||
$new);
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
38
src/applications/nuance/typeahead/NuanceQueueDatasource.php
Normal file
38
src/applications/nuance/typeahead/NuanceQueueDatasource.php
Normal file
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
final class NuanceQueueDatasource
|
||||
extends PhabricatorTypeaheadDatasource {
|
||||
|
||||
public function getBrowseTitle() {
|
||||
return pht('Browse Queues');
|
||||
}
|
||||
|
||||
public function getPlaceholderText() {
|
||||
return pht('Type a queue name...');
|
||||
}
|
||||
|
||||
public function getDatasourceApplicationClass() {
|
||||
return 'PhabricatorNuanceApplication';
|
||||
}
|
||||
|
||||
public function loadResults() {
|
||||
$viewer = $this->getViewer();
|
||||
$raw_query = $this->getRawQuery();
|
||||
|
||||
$results = array();
|
||||
|
||||
// TODO: Make this use real typeahead logic.
|
||||
$query = new NuanceQueueQuery();
|
||||
$queues = $this->executeQuery($query);
|
||||
|
||||
foreach ($queues as $queue) {
|
||||
$results[] = id(new PhabricatorTypeaheadResult())
|
||||
->setName($queue->getName())
|
||||
->setURI('/nuance/queue/'.$queue->getID().'/')
|
||||
->setPHID($queue->getPHID());
|
||||
}
|
||||
|
||||
return $this->filterResultsAgainstTokens($results);
|
||||
}
|
||||
|
||||
}
|
|
@ -28,19 +28,12 @@ final class PhabricatorProjectColumnQuery
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function newResultObject() {
|
||||
return new PhabricatorProjectColumn();
|
||||
}
|
||||
|
||||
protected function loadPage() {
|
||||
$table = new PhabricatorProjectColumn();
|
||||
$conn_r = $table->establishConnection('r');
|
||||
|
||||
$data = queryfx_all(
|
||||
$conn_r,
|
||||
'SELECT * FROM %T %Q %Q %Q',
|
||||
$table->getTableName(),
|
||||
$this->buildWhereClause($conn_r),
|
||||
$this->buildOrderClause($conn_r),
|
||||
$this->buildLimitClause($conn_r));
|
||||
|
||||
return $table->loadAllFromArray($data);
|
||||
return $this->loadStandardPage($this->newResultObject());
|
||||
}
|
||||
|
||||
protected function willFilterPage(array $page) {
|
||||
|
@ -60,6 +53,7 @@ final class PhabricatorProjectColumnQuery
|
|||
$phid = $column->getProjectPHID();
|
||||
$project = idx($projects, $phid);
|
||||
if (!$project) {
|
||||
$this->didRejectResult($page[$key]);
|
||||
unset($page[$key]);
|
||||
continue;
|
||||
}
|
||||
|
@ -69,40 +63,38 @@ final class PhabricatorProjectColumnQuery
|
|||
return $page;
|
||||
}
|
||||
|
||||
protected function buildWhereClause(AphrontDatabaseConnection $conn_r) {
|
||||
$where = array();
|
||||
protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
|
||||
$where = parent::buildWhereClauseParts($conn);
|
||||
|
||||
if ($this->ids) {
|
||||
if ($this->ids !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
$conn,
|
||||
'id IN (%Ld)',
|
||||
$this->ids);
|
||||
}
|
||||
|
||||
if ($this->phids) {
|
||||
if ($this->phids !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
$conn,
|
||||
'phid IN (%Ls)',
|
||||
$this->phids);
|
||||
}
|
||||
|
||||
if ($this->projectPHIDs) {
|
||||
if ($this->projectPHIDs !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
$conn,
|
||||
'projectPHID IN (%Ls)',
|
||||
$this->projectPHIDs);
|
||||
}
|
||||
|
||||
if ($this->statuses !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
$conn,
|
||||
'status IN (%Ld)',
|
||||
$this->statuses);
|
||||
}
|
||||
|
||||
$where[] = $this->buildPagingClause($conn_r);
|
||||
|
||||
return $this->formatWhereClause($where);
|
||||
return $where;
|
||||
}
|
||||
|
||||
public function getQueryApplicationClass() {
|
||||
|
|
|
@ -69,6 +69,8 @@ abstract class PhabricatorApplicationTransactionEditor
|
|||
private $feedNotifyPHIDs = array();
|
||||
private $feedRelatedPHIDs = array();
|
||||
|
||||
const STORAGE_ENCODING_BINARY = 'binary';
|
||||
|
||||
/**
|
||||
* Get the class name for the application this editor is a part of.
|
||||
*
|
||||
|
@ -2637,6 +2639,21 @@ abstract class PhabricatorApplicationTransactionEditor
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* @task mail
|
||||
*/
|
||||
private function runHeraldMailRules(array $messages) {
|
||||
foreach ($messages as $message) {
|
||||
$engine = new HeraldEngine();
|
||||
$adapter = id(new PhabricatorMailOutboundMailHeraldAdapter())
|
||||
->setObject($message);
|
||||
|
||||
$rules = $engine->loadRulesForAdapter($adapter);
|
||||
$effects = $engine->applyRules($rules, $adapter);
|
||||
$engine->applyEffects($effects, $adapter, $rules);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* -( Publishing Feed Stories )-------------------------------------------- */
|
||||
|
||||
|
@ -3060,9 +3077,13 @@ abstract class PhabricatorApplicationTransactionEditor
|
|||
$state[$property] = $this->$property;
|
||||
}
|
||||
|
||||
$custom_state = $this->getCustomWorkerState();
|
||||
$custom_encoding = $this->getCustomWorkerStateEncoding();
|
||||
|
||||
$state += array(
|
||||
'excludeMailRecipientPHIDs' => $this->getExcludeMailRecipientPHIDs(),
|
||||
'custom' => $this->getCustomWorkerState(),
|
||||
'custom' => $this->encodeStateForStorage($custom_state, $custom_encoding),
|
||||
'custom.encoding' => $custom_encoding,
|
||||
);
|
||||
|
||||
return $state;
|
||||
|
@ -3080,6 +3101,21 @@ abstract class PhabricatorApplicationTransactionEditor
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Hook; return storage encoding for custom properties which need to be
|
||||
* passed to workers.
|
||||
*
|
||||
* This primarily allows binary data to be passed to workers and survive
|
||||
* JSON encoding.
|
||||
*
|
||||
* @return dict<string, string> Property encodings.
|
||||
* @task workers
|
||||
*/
|
||||
protected function getCustomWorkerStateEncoding() {
|
||||
return array();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Load editor state using a dictionary emitted by @{method:getWorkerState}.
|
||||
*
|
||||
|
@ -3097,7 +3133,10 @@ abstract class PhabricatorApplicationTransactionEditor
|
|||
$exclude = idx($state, 'excludeMailRecipientPHIDs', array());
|
||||
$this->setExcludeMailRecipientPHIDs($exclude);
|
||||
|
||||
$custom = idx($state, 'custom', array());
|
||||
$custom_state = idx($state, 'custom', array());
|
||||
$custom_encodings = idx($state, 'custom.encoding', array());
|
||||
$custom = $this->decodeStateFromStorage($custom_state, $custom_encodings);
|
||||
|
||||
$this->loadCustomWorkerState($custom);
|
||||
|
||||
return $this;
|
||||
|
@ -3143,16 +3182,85 @@ abstract class PhabricatorApplicationTransactionEditor
|
|||
);
|
||||
}
|
||||
|
||||
private function runHeraldMailRules(array $messages) {
|
||||
foreach ($messages as $message) {
|
||||
$engine = new HeraldEngine();
|
||||
$adapter = id(new PhabricatorMailOutboundMailHeraldAdapter())
|
||||
->setObject($message);
|
||||
/**
|
||||
* Apply encodings prior to storage.
|
||||
*
|
||||
* See @{method:getCustomWorkerStateEncoding}.
|
||||
*
|
||||
* @param map<string, wild> Map of values to encode.
|
||||
* @param map<string, string> Map of encodings to apply.
|
||||
* @return map<string, wild> Map of encoded values.
|
||||
* @task workers
|
||||
*/
|
||||
final private function encodeStateForStorage(
|
||||
array $state,
|
||||
array $encodings) {
|
||||
|
||||
$rules = $engine->loadRulesForAdapter($adapter);
|
||||
$effects = $engine->applyRules($rules, $adapter);
|
||||
$engine->applyEffects($effects, $adapter, $rules);
|
||||
foreach ($state as $key => $value) {
|
||||
$encoding = idx($encodings, $key);
|
||||
switch ($encoding) {
|
||||
case self::STORAGE_ENCODING_BINARY:
|
||||
// The mechanics of this encoding (serialize + base64) are a little
|
||||
// awkward, but it allows us encode arrays and still be JSON-safe
|
||||
// with binary data.
|
||||
|
||||
$value = @serialize($value);
|
||||
if ($value === false) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Failed to serialize() value for key "%s".',
|
||||
$key));
|
||||
}
|
||||
|
||||
$value = base64_encode($value);
|
||||
if ($value === false) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Failed to base64 encode value for key "%s".',
|
||||
$key));
|
||||
}
|
||||
break;
|
||||
}
|
||||
$state[$key] = $value;
|
||||
}
|
||||
|
||||
return $state;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Undo storage encoding applied when storing state.
|
||||
*
|
||||
* See @{method:getCustomWorkerStateEncoding}.
|
||||
*
|
||||
* @param map<string, wild> Map of encoded values.
|
||||
* @param map<string, string> Map of encodings.
|
||||
* @return map<string, wild> Map of decoded values.
|
||||
* @task workers
|
||||
*/
|
||||
final private function decodeStateFromStorage(
|
||||
array $state,
|
||||
array $encodings) {
|
||||
|
||||
foreach ($state as $key => $value) {
|
||||
$encoding = idx($encodings, $key);
|
||||
switch ($encoding) {
|
||||
case self::STORAGE_ENCODING_BINARY:
|
||||
$value = base64_decode($value);
|
||||
if ($value === false) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Failed to base64_decode() value for key "%s".',
|
||||
$key));
|
||||
}
|
||||
|
||||
$value = unserialize($value);
|
||||
break;
|
||||
}
|
||||
$state[$key] = $value;
|
||||
}
|
||||
|
||||
return $state;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -26,9 +26,14 @@ final class PhabricatorApplicationTransactionPublishWorker
|
|||
* Load the object the transactions affect.
|
||||
*/
|
||||
private function loadObject() {
|
||||
$data = $this->getTaskData();
|
||||
$viewer = PhabricatorUser::getOmnipotentUser();
|
||||
|
||||
$data = $this->getTaskData();
|
||||
if (!is_array($data)) {
|
||||
throw new PhabricatorWorkerPermanentFailureException(
|
||||
pht('Task has invalid task data.'));
|
||||
}
|
||||
|
||||
$phid = idx($data, 'objectPHID');
|
||||
if (!$phid) {
|
||||
throw new PhabricatorWorkerPermanentFailureException(
|
||||
|
|
|
@ -65,7 +65,7 @@ write such a script, and run this command to see its output:
|
|||
To actually build the symbol index, pipe this data to the
|
||||
`import_repository_symbols.php` script, providing the repository callsign:
|
||||
|
||||
$ ./scripts/symbols/import_repository_symbols.php rREPO < symbols_data
|
||||
$ ./scripts/symbols/import_repository_symbols.php REPO < symbols_data
|
||||
|
||||
Then just set up a cronjob to run that however often you like.
|
||||
|
||||
|
|
|
@ -24,8 +24,8 @@ abstract class PhabricatorCustomFieldMonogramParser
|
|||
'(?:^|\b)'.
|
||||
$prefix_regex.
|
||||
$infix_regex.
|
||||
'((?:'.$monogram_pattern.'[,\s]*)+)'.
|
||||
'(?:\band\s+('.$monogram_pattern.'))?'.
|
||||
'((?:'.$monogram_pattern.'(?:\b|$)[,\s]*)+)'.
|
||||
'(?:\band\s+('.$monogram_pattern.'(?:\b|$)))?'.
|
||||
$suffix_regex.
|
||||
'(?:$|\b)'.
|
||||
'/';
|
||||
|
|
|
@ -1369,6 +1369,11 @@ final class PhabricatorUSEnglishTranslation
|
|||
'This action has no effect on targets: %2$s.',
|
||||
),
|
||||
|
||||
'Mail sent in the last %s day(s).' => array(
|
||||
'Mail sent in the last day.',
|
||||
'Mail sent in the last %s days.',
|
||||
),
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -44,6 +44,7 @@ final class PhabricatorMarkupEngine extends Phobject {
|
|||
private $contextObject;
|
||||
private $version = 15;
|
||||
private $engineCaches = array();
|
||||
private $auxiliaryConfig = array();
|
||||
|
||||
|
||||
/* -( Markup Pipeline )---------------------------------------------------- */
|
||||
|
@ -122,6 +123,10 @@ final class PhabricatorMarkupEngine extends Phobject {
|
|||
$engines[$key] = $info['object']->newMarkupEngine($info['field']);
|
||||
$engines[$key]->setConfig('viewer', $this->viewer);
|
||||
$engines[$key]->setConfig('contextObject', $this->contextObject);
|
||||
|
||||
foreach ($this->auxiliaryConfig as $aux_key => $aux_value) {
|
||||
$engines[$key]->setConfig($aux_key, $aux_value);
|
||||
}
|
||||
}
|
||||
|
||||
// Load or build the preprocessor caches.
|
||||
|
@ -310,6 +315,12 @@ final class PhabricatorMarkupEngine extends Phobject {
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function setAuxiliaryConfig($key, $value) {
|
||||
// TODO: This is gross and should be removed. Avoid use.
|
||||
$this->auxiliaryConfig[$key] = $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/* -( Engine Construction )------------------------------------------------ */
|
||||
|
||||
|
|
|
@ -1651,7 +1651,7 @@ abstract class LiskDAO extends Phobject {
|
|||
if ($deserialize) {
|
||||
$data[$col] = json_decode($data[$col], true);
|
||||
} else {
|
||||
$data[$col] = json_encode($data[$col]);
|
||||
$data[$col] = phutil_json_encode($data[$col]);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -40,8 +40,7 @@ JX.behavior('repository-crossreference', function(config, statics) {
|
|||
'tag:span',
|
||||
function(e) {
|
||||
if (e.getType() === 'mouseout') {
|
||||
highlighted && JX.DOM.alterClass(highlighted, classHighlight, false);
|
||||
highlighted = null;
|
||||
unhighlight();
|
||||
return;
|
||||
}
|
||||
if (!isSignalkey(e)) {
|
||||
|
@ -59,10 +58,14 @@ JX.behavior('repository-crossreference', function(config, statics) {
|
|||
target = target.parentNode;
|
||||
}
|
||||
} else if (e.getType() === 'click') {
|
||||
openSearch(highlighted, lang);
|
||||
openSearch(e.getTarget(), lang);
|
||||
}
|
||||
});
|
||||
}
|
||||
function unhighlight() {
|
||||
highlighted && JX.DOM.alterClass(highlighted, classHighlight, false);
|
||||
highlighted = null;
|
||||
}
|
||||
|
||||
function openSearch(target, lang) {
|
||||
var symbol = target.textContent || target.innerText;
|
||||
|
@ -110,6 +113,7 @@ JX.behavior('repository-crossreference', function(config, statics) {
|
|||
linkAll(e.getData().container);
|
||||
});
|
||||
|
||||
|
||||
JX.Stratcom.listen(
|
||||
['keydown', 'keyup'],
|
||||
null,
|
||||
|
@ -117,14 +121,28 @@ JX.behavior('repository-crossreference', function(config, statics) {
|
|||
if (e.getRawEvent().keyCode !== signalKey) {
|
||||
return;
|
||||
}
|
||||
statics.active = (e.getType() === 'keydown');
|
||||
linked.forEach(function(element) {
|
||||
JX.DOM.alterClass(element, classMouseCursor, statics.active);
|
||||
});
|
||||
setCursorMode(e.getType() === 'keydown');
|
||||
|
||||
if (!statics.active) {
|
||||
highlighted && JX.DOM.alterClass(highlighted, classHighlight, false);
|
||||
highlighted = null;
|
||||
unhighlight();
|
||||
}
|
||||
});
|
||||
|
||||
JX.Stratcom.listen(
|
||||
'blur',
|
||||
null,
|
||||
function(e) {
|
||||
if (e.getTarget()) {
|
||||
return;
|
||||
}
|
||||
unhighlight();
|
||||
setCursorMode(false);
|
||||
});
|
||||
|
||||
function setCursorMode(active) {
|
||||
statics.active = active;
|
||||
linked.forEach(function(element) {
|
||||
JX.DOM.alterClass(element, classMouseCursor, statics.active);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue