diff --git a/resources/sql/autopatches/20150610.spaces.3.archive.sql b/resources/sql/autopatches/20150610.spaces.3.archive.sql new file mode 100644 index 0000000000..8dd55959a3 --- /dev/null +++ b/resources/sql/autopatches/20150610.spaces.3.archive.sql @@ -0,0 +1,2 @@ +ALTER TABLE {$NAMESPACE}_spaces.spaces_namespace + ADD isArchived BOOL NOT NULL; diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index e3ba379280..079819f657 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -2577,6 +2577,7 @@ phutil_register_library_map(array( 'PhabricatorSortTableUIExample' => 'applications/uiexample/examples/PhabricatorSortTableUIExample.php', 'PhabricatorSourceCodeView' => 'view/layout/PhabricatorSourceCodeView.php', 'PhabricatorSpacesApplication' => 'applications/spaces/application/PhabricatorSpacesApplication.php', + 'PhabricatorSpacesArchiveController' => 'applications/spaces/controller/PhabricatorSpacesArchiveController.php', 'PhabricatorSpacesCapabilityCreateSpaces' => 'applications/spaces/capability/PhabricatorSpacesCapabilityCreateSpaces.php', 'PhabricatorSpacesCapabilityDefaultEdit' => 'applications/spaces/capability/PhabricatorSpacesCapabilityDefaultEdit.php', 'PhabricatorSpacesCapabilityDefaultView' => 'applications/spaces/capability/PhabricatorSpacesCapabilityDefaultView.php', @@ -6089,6 +6090,7 @@ phutil_register_library_map(array( 'PhabricatorSortTableUIExample' => 'PhabricatorUIExample', 'PhabricatorSourceCodeView' => 'AphrontView', 'PhabricatorSpacesApplication' => 'PhabricatorApplication', + 'PhabricatorSpacesArchiveController' => 'PhabricatorSpacesController', 'PhabricatorSpacesCapabilityCreateSpaces' => 'PhabricatorPolicyCapability', 'PhabricatorSpacesCapabilityDefaultEdit' => 'PhabricatorPolicyCapability', 'PhabricatorSpacesCapabilityDefaultView' => 'PhabricatorPolicyCapability', diff --git a/src/applications/people/storage/PhabricatorUser.php b/src/applications/people/storage/PhabricatorUser.php index aa93485dd2..55ade255a7 100644 --- a/src/applications/people/storage/PhabricatorUser.php +++ b/src/applications/people/storage/PhabricatorUser.php @@ -759,7 +759,7 @@ final class PhabricatorUser // for now just use the global space if one exists. // If the viewer has access to the default space, use that. - $spaces = PhabricatorSpacesNamespaceQuery::getViewerSpaces($this); + $spaces = PhabricatorSpacesNamespaceQuery::getViewerActiveSpaces($this); foreach ($spaces as $space) { if ($space->getIsDefaultNamespace()) { return $space->getPHID(); diff --git a/src/applications/search/engine/PhabricatorApplicationSearchEngine.php b/src/applications/search/engine/PhabricatorApplicationSearchEngine.php index 5d0f79e170..453b965034 100644 --- a/src/applications/search/engine/PhabricatorApplicationSearchEngine.php +++ b/src/applications/search/engine/PhabricatorApplicationSearchEngine.php @@ -149,6 +149,10 @@ abstract class PhabricatorApplicationSearchEngine extends Phobject { if ($object instanceof PhabricatorSpacesInterface) { if (!empty($map['spacePHIDs'])) { $query->withSpacePHIDs($map['spacePHIDs']); + } else { + // If the user doesn't search for objects in specific spaces, we + // default to "all active spaces you have permission to view". + $query->withSpaceIsArchived(false); } } diff --git a/src/applications/spaces/application/PhabricatorSpacesApplication.php b/src/applications/spaces/application/PhabricatorSpacesApplication.php index 380f80569e..0e25120626 100644 --- a/src/applications/spaces/application/PhabricatorSpacesApplication.php +++ b/src/applications/spaces/application/PhabricatorSpacesApplication.php @@ -38,6 +38,15 @@ final class PhabricatorSpacesApplication extends PhabricatorApplication { return true; } + public function getHelpDocumentationArticles(PhabricatorUser $viewer) { + return array( + array( + 'name' => pht('Spaces User Guide'), + 'href' => PhabricatorEnv::getDoclink('Spaces User Guide'), + ), + ); + } + public function getRemarkupRules() { return array( new PhabricatorSpacesRemarkupRule(), @@ -51,6 +60,8 @@ final class PhabricatorSpacesApplication extends PhabricatorApplication { '(?:query/(?P[^/]+)/)?' => 'PhabricatorSpacesListController', 'create/' => 'PhabricatorSpacesEditController', 'edit/(?:(?P\d+)/)?' => 'PhabricatorSpacesEditController', + '(?Pactivate|archive)/(?P\d+)/' + => 'PhabricatorSpacesArchiveController', ), ); } diff --git a/src/applications/spaces/controller/PhabricatorSpacesArchiveController.php b/src/applications/spaces/controller/PhabricatorSpacesArchiveController.php new file mode 100644 index 0000000000..82cf19e9e8 --- /dev/null +++ b/src/applications/spaces/controller/PhabricatorSpacesArchiveController.php @@ -0,0 +1,76 @@ +getUser(); + + $space = id(new PhabricatorSpacesNamespaceQuery()) + ->setViewer($viewer) + ->withIDs(array($request->getURIData('id'))) + ->requireCapabilities( + array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + )) + ->executeOne(); + if (!$space) { + return new Aphront404Response(); + } + + $is_archive = ($request->getURIData('action') == 'archive'); + $cancel_uri = '/'.$space->getMonogram(); + + if ($request->isFormPost()) { + $type_archive = PhabricatorSpacesNamespaceTransaction::TYPE_ARCHIVE; + + $xactions = array(); + $xactions[] = id(new PhabricatorSpacesNamespaceTransaction()) + ->setTransactionType($type_archive) + ->setNewValue($is_archive ? 1 : 0); + + $editor = id(new PhabricatorSpacesNamespaceEditor()) + ->setActor($viewer) + ->setContinueOnNoEffect(true) + ->setContinueOnMissingFields(true) + ->setContentSourceFromRequest($request); + + $editor->applyTransactions($space, $xactions); + + return id(new AphrontRedirectResponse())->setURI($cancel_uri); + } + + $body = array(); + if ($is_archive) { + $title = pht('Archive Space: %s', $space->getNamespaceName()); + $body[] = pht( + 'If you archive this Space, you will no longer be able to create '. + 'new objects inside it.'); + $body[] = pht( + 'Existing objects in this Space will be hidden from query results '. + 'by default.'); + $button = pht('Archive Space'); + } else { + $title = pht('Activate Space: %s', $space->getNamespaceName()); + $body[] = pht( + 'If you activate this space, you will be able to create objects '. + 'inside it again.'); + $body[] = pht( + 'Existing objects will no longer be hidden from query results.'); + $button = pht('Activate Space'); + } + + + $dialog = $this->newDialog() + ->setTitle($title) + ->addCancelButton($cancel_uri) + ->addSubmitButton($button); + + foreach ($body as $paragraph) { + $dialog->appendParagraph($paragraph); + } + + return $dialog; + } +} diff --git a/src/applications/spaces/controller/PhabricatorSpacesViewController.php b/src/applications/spaces/controller/PhabricatorSpacesViewController.php index 46e82627ec..511d853151 100644 --- a/src/applications/spaces/controller/PhabricatorSpacesViewController.php +++ b/src/applications/spaces/controller/PhabricatorSpacesViewController.php @@ -37,6 +37,12 @@ final class PhabricatorSpacesViewController ->setHeader($space->getNamespaceName()) ->setPolicyObject($space); + if ($space->getIsArchived()) { + $header->setStatus('fa-ban', 'red', pht('Archived')); + } else { + $header->setStatus('fa-check', 'bluegrey', pht('Active')); + } + $box = id(new PHUIObjectBoxView()) ->setHeader($header) ->addPropertyList($property_list); @@ -112,6 +118,26 @@ final class PhabricatorSpacesViewController ->setWorkflow(!$can_edit) ->setDisabled(!$can_edit)); + $id = $space->getID(); + + if ($space->getIsArchived()) { + $list->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Activate Space')) + ->setIcon('fa-check') + ->setHref($this->getApplicationURI("activate/{$id}/")) + ->setDisabled(!$can_edit) + ->setWorkflow(true)); + } else { + $list->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Archive Space')) + ->setIcon('fa-ban') + ->setHref($this->getApplicationURI("archive/{$id}/")) + ->setDisabled(!$can_edit) + ->setWorkflow(true)); + } + return $list; } diff --git a/src/applications/spaces/editor/PhabricatorSpacesNamespaceEditor.php b/src/applications/spaces/editor/PhabricatorSpacesNamespaceEditor.php index 3b6c7bb6e6..caa45f28c2 100644 --- a/src/applications/spaces/editor/PhabricatorSpacesNamespaceEditor.php +++ b/src/applications/spaces/editor/PhabricatorSpacesNamespaceEditor.php @@ -17,6 +17,7 @@ final class PhabricatorSpacesNamespaceEditor $types[] = PhabricatorSpacesNamespaceTransaction::TYPE_NAME; $types[] = PhabricatorSpacesNamespaceTransaction::TYPE_DESCRIPTION; $types[] = PhabricatorSpacesNamespaceTransaction::TYPE_DEFAULT; + $types[] = PhabricatorSpacesNamespaceTransaction::TYPE_ARCHIVE; $types[] = PhabricatorTransactions::TYPE_VIEW_POLICY; $types[] = PhabricatorTransactions::TYPE_EDIT_POLICY; @@ -40,6 +41,8 @@ final class PhabricatorSpacesNamespaceEditor return null; } return $object->getDescription(); + case PhabricatorSpacesNamespaceTransaction::TYPE_ARCHIVE: + return $object->getIsArchived(); case PhabricatorSpacesNamespaceTransaction::TYPE_DEFAULT: return $object->getIsDefaultNamespace() ? 1 : null; case PhabricatorTransactions::TYPE_VIEW_POLICY: @@ -61,6 +64,8 @@ final class PhabricatorSpacesNamespaceEditor case PhabricatorTransactions::TYPE_VIEW_POLICY: case PhabricatorTransactions::TYPE_EDIT_POLICY: return $xaction->getNewValue(); + case PhabricatorSpacesNamespaceTransaction::TYPE_ARCHIVE: + return $xaction->getNewValue() ? 1 : 0; case PhabricatorSpacesNamespaceTransaction::TYPE_DEFAULT: return $xaction->getNewValue() ? 1 : null; } @@ -84,6 +89,9 @@ final class PhabricatorSpacesNamespaceEditor case PhabricatorSpacesNamespaceTransaction::TYPE_DEFAULT: $object->setIsDefaultNamespace($new ? 1 : null); return; + case PhabricatorSpacesNamespaceTransaction::TYPE_ARCHIVE: + $object->setIsArchived($new ? 1 : 0); + return; case PhabricatorTransactions::TYPE_VIEW_POLICY: $object->setViewPolicy($new); return; @@ -103,6 +111,7 @@ final class PhabricatorSpacesNamespaceEditor case PhabricatorSpacesNamespaceTransaction::TYPE_NAME: case PhabricatorSpacesNamespaceTransaction::TYPE_DESCRIPTION: case PhabricatorSpacesNamespaceTransaction::TYPE_DEFAULT: + case PhabricatorSpacesNamespaceTransaction::TYPE_ARCHIVE: case PhabricatorTransactions::TYPE_VIEW_POLICY: case PhabricatorTransactions::TYPE_EDIT_POLICY: return; @@ -128,13 +137,27 @@ final class PhabricatorSpacesNamespaceEditor $error = new PhabricatorApplicationTransactionValidationError( $type, pht('Required'), - pht('Spaces must have a name.'), + pht('Spaces must have a name.'), nonempty(last($xactions), null)); $error->setIsMissingFieldError(true); $errors[] = $error; } break; + case PhabricatorSpacesNamespaceTransaction::TYPE_DEFAULT: + if (!$this->getIsNewObject()) { + foreach ($xactions as $xaction) { + $errors[] = new PhabricatorApplicationTransactionValidationError( + $type, + pht('Invalid'), + pht( + 'Only the first space created can be the default space, and '. + 'it must remain the default space evermore.'), + $xaction); + } + } + break; + } return $errors; diff --git a/src/applications/spaces/phid/PhabricatorSpacesNamespacePHIDType.php b/src/applications/spaces/phid/PhabricatorSpacesNamespacePHIDType.php index 710972e8f4..6645c7edbd 100644 --- a/src/applications/spaces/phid/PhabricatorSpacesNamespacePHIDType.php +++ b/src/applications/spaces/phid/PhabricatorSpacesNamespacePHIDType.php @@ -39,6 +39,10 @@ final class PhabricatorSpacesNamespacePHIDType $handle->setName($name); $handle->setFullName(pht('%s %s', $monogram, $name)); $handle->setURI('/'.$monogram); + + if ($namespace->getIsArchived()) { + $handle->setStatus(PhabricatorObjectHandle::STATUS_CLOSED); + } } } diff --git a/src/applications/spaces/query/PhabricatorSpacesNamespaceQuery.php b/src/applications/spaces/query/PhabricatorSpacesNamespaceQuery.php index 77cb8aee5e..51ac66130a 100644 --- a/src/applications/spaces/query/PhabricatorSpacesNamespaceQuery.php +++ b/src/applications/spaces/query/PhabricatorSpacesNamespaceQuery.php @@ -9,6 +9,7 @@ final class PhabricatorSpacesNamespaceQuery private $ids; private $phids; private $isDefaultNamespace; + private $isArchived; public function withIDs(array $ids) { $this->ids = $ids; @@ -25,38 +26,32 @@ final class PhabricatorSpacesNamespaceQuery return $this; } + public function withIsArchived($archived) { + $this->isArchived = $archived; + return $this; + } + public function getQueryApplicationClass() { return 'PhabricatorSpacesApplication'; } protected function loadPage() { - $table = new PhabricatorSpacesNamespace(); - $conn_r = $table->establishConnection('r'); - - $rows = 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($rows); + return $this->loadStandardPage(new PhabricatorSpacesNamespace()); } - protected function buildWhereClause(AphrontDatabaseConnection $conn_r) { - $where = array(); + protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { + $where = parent::buildWhereClauseParts($conn); if ($this->ids !== null) { $where[] = qsprintf( - $conn_r, + $conn, 'id IN (%Ld)', $this->ids); } if ($this->phids !== null) { $where[] = qsprintf( - $conn_r, + $conn, 'phid IN (%Ls)', $this->phids); } @@ -64,17 +59,23 @@ final class PhabricatorSpacesNamespaceQuery if ($this->isDefaultNamespace !== null) { if ($this->isDefaultNamespace) { $where[] = qsprintf( - $conn_r, + $conn, 'isDefaultNamespace = 1'); } else { $where[] = qsprintf( - $conn_r, + $conn, 'isDefaultNamespace IS NULL'); } } - $where[] = $this->buildPagingClause($conn_r); - return $this->formatWhereClause($where); + if ($this->isArchived !== null) { + $where[] = qsprintf( + $conn, + 'isArchived = %d', + (int)$this->isArchived); + } + + return $where; } public static function destroySpacesCache() { @@ -156,6 +157,21 @@ final class PhabricatorSpacesNamespaceQuery return $result; } + + public static function getViewerActiveSpaces(PhabricatorUser $viewer) { + $spaces = self::getViewerSpaces($viewer); + + foreach ($spaces as $key => $space) { + if ($space->getIsArchived()) { + unset($spaces[$key]); + } + } + + return $spaces; + } + + + /** * Get the Space PHID for an object, if one exists. * diff --git a/src/applications/spaces/query/PhabricatorSpacesNamespaceSearchEngine.php b/src/applications/spaces/query/PhabricatorSpacesNamespaceSearchEngine.php index 9b4014c3dd..c12ad9e098 100644 --- a/src/applications/spaces/query/PhabricatorSpacesNamespaceSearchEngine.php +++ b/src/applications/spaces/query/PhabricatorSpacesNamespaceSearchEngine.php @@ -11,28 +11,39 @@ final class PhabricatorSpacesNamespaceSearchEngine return pht('Spaces'); } - public function buildSavedQueryFromRequest(AphrontRequest $request) { - $saved = new PhabricatorSavedQuery(); - - return $saved; + public function newQuery() { + return new PhabricatorSpacesNamespaceQuery(); } - public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) { - $query = id(new PhabricatorSpacesNamespaceQuery()); + public function buildCustomSearchFields() { + return array( + id(new PhabricatorSearchThreeStateField()) + ->setLabel(pht('Active')) + ->setKey('active') + ->setOptions( + pht('(Show All)'), + pht('Show Only Active Spaces'), + pht('Hide Active Spaces')), + ); + } + + public function buildQueryFromParameters(array $map) { + $query = $this->newQuery(); + + if ($map['active']) { + $query->withIsArchived(!$map['active']); + } return $query; } - public function buildSearchForm( - AphrontFormView $form, - PhabricatorSavedQuery $saved_query) {} - protected function getURI($path) { return '/spaces/'.$path; } protected function getBuiltinQueryNames() { $names = array( + 'active' => pht('Active Spaces'), 'all' => pht('All Spaces'), ); @@ -40,11 +51,12 @@ final class PhabricatorSpacesNamespaceSearchEngine } public function buildSavedQueryFromBuiltin($query_key) { - $query = $this->newSavedQuery(); $query->setQueryKey($query_key); switch ($query_key) { + case 'active': + return $query->setParameter('active', true); case 'all': return $query; } @@ -72,6 +84,10 @@ final class PhabricatorSpacesNamespaceSearchEngine $item->addIcon('fa-certificate', pht('Default Space')); } + if ($space->getIsArchived()) { + $item->setDisabled(true); + } + $list->addItem($item); } diff --git a/src/applications/spaces/storage/PhabricatorSpacesNamespace.php b/src/applications/spaces/storage/PhabricatorSpacesNamespace.php index 5b1098b1f8..f728d22dfa 100644 --- a/src/applications/spaces/storage/PhabricatorSpacesNamespace.php +++ b/src/applications/spaces/storage/PhabricatorSpacesNamespace.php @@ -12,6 +12,7 @@ final class PhabricatorSpacesNamespace protected $editPolicy; protected $isDefaultNamespace; protected $description; + protected $isArchived; public static function initializeNewNamespace(PhabricatorUser $actor) { $app = id(new PhabricatorApplicationQuery()) @@ -28,7 +29,8 @@ final class PhabricatorSpacesNamespace ->setIsDefaultNamespace(null) ->setViewPolicy($view_policy) ->setEditPolicy($edit_policy) - ->setDescription(''); + ->setDescription('') + ->setIsArchived(0); } protected function getConfiguration() { @@ -38,6 +40,7 @@ final class PhabricatorSpacesNamespace 'namespaceName' => 'text255', 'isDefaultNamespace' => 'bool?', 'description' => 'text', + 'isArchived' => 'bool', ), self::CONFIG_KEY_SCHEMA => array( 'key_default' => array( diff --git a/src/applications/spaces/storage/PhabricatorSpacesNamespaceTransaction.php b/src/applications/spaces/storage/PhabricatorSpacesNamespaceTransaction.php index ef7d8f210f..4c438537f1 100644 --- a/src/applications/spaces/storage/PhabricatorSpacesNamespaceTransaction.php +++ b/src/applications/spaces/storage/PhabricatorSpacesNamespaceTransaction.php @@ -6,6 +6,7 @@ final class PhabricatorSpacesNamespaceTransaction const TYPE_NAME = 'spaces:name'; const TYPE_DEFAULT = 'spaces:default'; const TYPE_DESCRIPTION = 'spaces:description'; + const TYPE_ARCHIVE = 'spaces:archive'; public function getApplicationName() { return 'spaces'; @@ -78,6 +79,16 @@ final class PhabricatorSpacesNamespaceTransaction return pht( '%s made this the default space.', $this->renderHandleLink($author_phid)); + case self::TYPE_ARCHIVE: + if ($new) { + return pht( + '%s archived this space.', + $this->renderHandleLink($author_phid)); + } else { + return pht( + '%s activated this space.', + $this->renderHandleLink($author_phid)); + } } return parent::getTitle(); diff --git a/src/applications/spaces/typeahead/PhabricatorSpacesNamespaceDatasource.php b/src/applications/spaces/typeahead/PhabricatorSpacesNamespaceDatasource.php index 046e3b0f4f..25951b53af 100644 --- a/src/applications/spaces/typeahead/PhabricatorSpacesNamespaceDatasource.php +++ b/src/applications/spaces/typeahead/PhabricatorSpacesNamespaceDatasource.php @@ -21,9 +21,20 @@ final class PhabricatorSpacesNamespaceDatasource $spaces = $this->executeQuery($query); $results = array(); foreach ($spaces as $space) { - $results[] = id(new PhabricatorTypeaheadResult()) - ->setName($space->getNamespaceName()) + $full_name = pht( + '%s %s', + $space->getMonogram(), + $space->getNamespaceName()); + + $result = id(new PhabricatorTypeaheadResult()) + ->setName($full_name) ->setPHID($space->getPHID()); + + if ($space->getIsArchived()) { + $result->setClosed(pht('Archived')); + } + + $results[] = $result; } return $this->filterResultsAgainstTokens($results); diff --git a/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php b/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php index b4d36b5513..2f36828b8a 100644 --- a/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php +++ b/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php @@ -310,6 +310,7 @@ abstract class PhabricatorApplicationTransactionEditor $space_phid = $default_space->getPHID(); } } + return $space_phid; case PhabricatorTransactions::TYPE_EDGE: $edge_type = $xaction->getMetadataValue('edge:type'); @@ -2011,6 +2012,8 @@ abstract class PhabricatorApplicationTransactionEditor $has_spaces = PhabricatorSpacesNamespaceQuery::getViewerSpacesExist($actor); $actor_spaces = PhabricatorSpacesNamespaceQuery::getViewerSpaces($actor); + $active_spaces = PhabricatorSpacesNamespaceQuery::getViewerActiveSpaces( + $actor); foreach ($xactions as $xaction) { $space_phid = $xaction->getNewValue(); @@ -2040,6 +2043,23 @@ abstract class PhabricatorApplicationTransactionEditor 'You can not shift this object in the selected space, because '. 'the space does not exist or you do not have access to it.'), $xaction); + } else if (empty($active_spaces[$space_phid])) { + + // It's OK to edit objects in an archived space, so just move on if + // we aren't adjusting the value. + $old_space_phid = $this->getTransactionOldValue($object, $xaction); + if ($space_phid == $old_space_phid) { + continue; + } + + $errors[] = new PhabricatorApplicationTransactionValidationError( + $transaction_type, + pht('Archived'), + pht( + 'You can not shift this object into the selected space, because '. + 'the space is archived. Objects can not be created inside (or '. + 'moved into) archived spaces.'), + $xaction); } } diff --git a/src/docs/user/userguide/spaces.diviner b/src/docs/user/userguide/spaces.diviner new file mode 100644 index 0000000000..9026edf86e --- /dev/null +++ b/src/docs/user/userguide/spaces.diviner @@ -0,0 +1,27 @@ +@title Spaces User Guide +@group userguide + +Guide to the Spaces application. + +Overview +======== + +IMPORTANT: Spaces is a prototype application. + +Archiving Spaces +================ + +If you no longer need a Space, you can archive it by choosing +{nav Archive Space} from the detail view. This hides the space and all the +objects in it without deleting any data. + +New objects can't be created into archived spaces, and existing objects can't +be shifted into archived spaces. The UI won't give you options to choose +these spaces when creating or editing objects. + +Additionally, objects (like tasks) in archived spaces won't be shown in most +search result lists by default. If you need to find objects in an archived +space, use the `Spaces` constraint to specifically search for objects in that +space. + +You can reactivate a space later by choosing {nav Activate Space}. diff --git a/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php b/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php index b48e1e5c46..4d0f96bde5 100644 --- a/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php +++ b/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php @@ -25,6 +25,7 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery private $edgeLogicConstraints = array(); private $edgeLogicConstraintsAreValid = false; private $spacePHIDs; + private $spaceIsArchived; protected function getPageCursors(array $page) { return array( @@ -1722,6 +1723,11 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery return $this; } + public function withSpaceIsArchived($archived) { + $this->spaceIsArchived = $archived; + return $this; + } + /** * Constrain the query to include only results in valid Spaces. @@ -1760,6 +1766,11 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery $viewer_spaces = PhabricatorSpacesNamespaceQuery::getViewerSpaces( $viewer); foreach ($viewer_spaces as $viewer_space) { + if ($this->spaceIsArchived !== null) { + if ($viewer_space->getIsArchived() != $this->spaceIsArchived) { + continue; + } + } $phid = $viewer_space->getPHID(); $space_phids[$phid] = $phid; if ($viewer_space->getIsDefaultNamespace()) { diff --git a/src/view/form/control/AphrontFormPolicyControl.php b/src/view/form/control/AphrontFormPolicyControl.php index 45bff0900e..58d06cc5de 100644 --- a/src/view/form/control/AphrontFormPolicyControl.php +++ b/src/view/form/control/AphrontFormPolicyControl.php @@ -265,7 +265,7 @@ final class AphrontFormPolicyControl extends AphrontFormControl { $select = AphrontFormSelectControl::renderSelectTag( $space_phid, - $this->getSpaceOptions(), + $this->getSpaceOptions($space_phid), array( 'name' => 'spacePHID', )); @@ -273,12 +273,20 @@ final class AphrontFormPolicyControl extends AphrontFormControl { return $select; } - protected function getSpaceOptions() { + protected function getSpaceOptions($space_phid) { $viewer = $this->getUser(); $viewer_spaces = PhabricatorSpacesNamespaceQuery::getViewerSpaces($viewer); $map = array(); foreach ($viewer_spaces as $space) { + + // Skip archived spaces, unless the object is already in that space. + if ($space->getIsArchived()) { + if ($space->getPHID() != $space_phid) { + continue; + } + } + $map[$space->getPHID()] = pht( 'Space %s: %s', $space->getMonogram(),