mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-19 12:00:55 +01:00
Frame workboard empty/create states inside profile menu
Summary: Ref T10054. Uncreated workboards feel a little awkward right now because you lose the menu. Instead, keep the menu. I also plan to: - add a "[X] Make the workboard the default view for this project." checkbox; and - resolve T6961. ...which will touch this workflow, so modernize/straighten it out. Test Plan: Viewed workboard, no access state, empty state. Created empty board, imported board. {F1066973} Reviewers: chad Reviewed By: chad Maniphest Tasks: T6961, T10054 Differential Revision: https://secure.phabricator.com/D15091
This commit is contained in:
parent
df4b484a5f
commit
b64d67f47a
1 changed files with 143 additions and 106 deletions
|
@ -19,50 +19,16 @@ final class PhabricatorProjectBoardViewController
|
||||||
|
|
||||||
public function handleRequest(AphrontRequest $request) {
|
public function handleRequest(AphrontRequest $request) {
|
||||||
$viewer = $request->getUser();
|
$viewer = $request->getUser();
|
||||||
$id = $request->getURIData('id');
|
|
||||||
|
|
||||||
$show_hidden = $request->getBool('hidden');
|
$response = $this->loadProject();
|
||||||
$this->showHidden = $show_hidden;
|
if ($response) {
|
||||||
|
return $response;
|
||||||
$project = id(new PhabricatorProjectQuery())
|
|
||||||
->setViewer($viewer)
|
|
||||||
->needImages(true);
|
|
||||||
$id = $request->getURIData('id');
|
|
||||||
$slug = $request->getURIData('slug');
|
|
||||||
if ($slug) {
|
|
||||||
$project->withSlugs(array($slug));
|
|
||||||
} else {
|
|
||||||
$project->withIDs(array($id));
|
|
||||||
}
|
|
||||||
$project = $project->executeOne();
|
|
||||||
if (!$project) {
|
|
||||||
return new Aphront404Response();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->setProject($project);
|
$project = $this->getProject();
|
||||||
$this->id = $project->getID();
|
|
||||||
|
|
||||||
$sort_key = $request->getStr('order');
|
$this->readRequestState();
|
||||||
switch ($sort_key) {
|
$columns = $this->loadColumns($project);
|
||||||
case PhabricatorProjectColumn::ORDER_NATURAL:
|
|
||||||
case PhabricatorProjectColumn::ORDER_PRIORITY:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
$sort_key = PhabricatorProjectColumn::DEFAULT_ORDER;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
$this->sortKey = $sort_key;
|
|
||||||
|
|
||||||
$column_query = id(new PhabricatorProjectColumnQuery())
|
|
||||||
->setViewer($viewer)
|
|
||||||
->withProjectPHIDs(array($project->getPHID()));
|
|
||||||
if (!$show_hidden) {
|
|
||||||
$column_query->withStatuses(
|
|
||||||
array(PhabricatorProjectColumn::STATUS_ACTIVE));
|
|
||||||
}
|
|
||||||
|
|
||||||
$columns = $column_query->execute();
|
|
||||||
$columns = mpull($columns, null, 'getSequence');
|
|
||||||
|
|
||||||
// TODO: Expand the checks here if we add the ability
|
// TODO: Expand the checks here if we add the ability
|
||||||
// to hide the Backlog column
|
// to hide the Backlog column
|
||||||
|
@ -72,32 +38,31 @@ final class PhabricatorProjectBoardViewController
|
||||||
$project,
|
$project,
|
||||||
PhabricatorPolicyCapability::CAN_EDIT);
|
PhabricatorPolicyCapability::CAN_EDIT);
|
||||||
if (!$can_edit) {
|
if (!$can_edit) {
|
||||||
return $this->noAccessDialog($project);
|
$content = $this->buildNoAccessContent($project);
|
||||||
}
|
} else {
|
||||||
switch ($request->getStr('initialize-type')) {
|
$content = $this->buildInitializeContent($project);
|
||||||
case 'backlog-only':
|
|
||||||
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
|
|
||||||
$column = PhabricatorProjectColumn::initializeNewColumn($viewer)
|
|
||||||
->setSequence(0)
|
|
||||||
->setProperty('isDefault', true)
|
|
||||||
->setProjectPHID($project->getPHID())
|
|
||||||
->save();
|
|
||||||
$column->attachProject($project);
|
|
||||||
$columns[0] = $column;
|
|
||||||
unset($unguarded);
|
|
||||||
break;
|
|
||||||
case 'import':
|
|
||||||
return id(new AphrontRedirectResponse())
|
|
||||||
->setURI(
|
|
||||||
$this->getApplicationURI('board/'.$project->getID().'/import/'));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return $this->initializeWorkboardDialog($project);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ksort($columns);
|
if ($content instanceof AphrontResponse) {
|
||||||
|
return $content;
|
||||||
|
}
|
||||||
|
|
||||||
|
$nav = $this->getProfileMenu();
|
||||||
|
$nav->selectFilter(PhabricatorProject::PANEL_WORKBOARD);
|
||||||
|
|
||||||
|
$crumbs = $this->buildApplicationCrumbs();
|
||||||
|
$crumbs->addTextCrumb(pht('Workboard'));
|
||||||
|
|
||||||
|
return $this->newPage()
|
||||||
|
->setTitle(
|
||||||
|
array(
|
||||||
|
pht('Workboard'),
|
||||||
|
$project->getName(),
|
||||||
|
))
|
||||||
|
->setNavigation($nav)
|
||||||
|
->setCrumbs($crumbs)
|
||||||
|
->appendChild($content);
|
||||||
|
}
|
||||||
|
|
||||||
$board_uri = $this->getApplicationURI('board/'.$project->getID().'/');
|
$board_uri = $this->getApplicationURI('board/'.$project->getID().'/');
|
||||||
|
|
||||||
|
@ -350,7 +315,7 @@ final class PhabricatorProjectBoardViewController
|
||||||
|
|
||||||
$sort_menu = $this->buildSortMenu(
|
$sort_menu = $this->buildSortMenu(
|
||||||
$viewer,
|
$viewer,
|
||||||
$sort_key);
|
$this->sortKey);
|
||||||
|
|
||||||
$filter_menu = $this->buildFilterMenu(
|
$filter_menu = $this->buildFilterMenu(
|
||||||
$viewer,
|
$viewer,
|
||||||
|
@ -358,7 +323,7 @@ final class PhabricatorProjectBoardViewController
|
||||||
$engine,
|
$engine,
|
||||||
$query_key);
|
$query_key);
|
||||||
|
|
||||||
$manage_menu = $this->buildManageMenu($project, $show_hidden);
|
$manage_menu = $this->buildManageMenu($project, $this->showHidden);
|
||||||
|
|
||||||
$header_link = phutil_tag(
|
$header_link = phutil_tag(
|
||||||
'a',
|
'a',
|
||||||
|
@ -402,6 +367,44 @@ final class PhabricatorProjectBoardViewController
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function readRequestState() {
|
||||||
|
$request = $this->getRequest();
|
||||||
|
$project = $this->getProject();
|
||||||
|
|
||||||
|
$this->showHidden = $request->getBool('hidden');
|
||||||
|
$this->id = $project->getID();
|
||||||
|
|
||||||
|
$sort_key = $request->getStr('order');
|
||||||
|
switch ($sort_key) {
|
||||||
|
case PhabricatorProjectColumn::ORDER_NATURAL:
|
||||||
|
case PhabricatorProjectColumn::ORDER_PRIORITY:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$sort_key = PhabricatorProjectColumn::DEFAULT_ORDER;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$this->sortKey = $sort_key;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function loadColumns(PhabricatorProject $project) {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
$column_query = id(new PhabricatorProjectColumnQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withProjectPHIDs(array($project->getPHID()));
|
||||||
|
|
||||||
|
if (!$this->showHidden) {
|
||||||
|
$column_query->withStatuses(
|
||||||
|
array(PhabricatorProjectColumn::STATUS_ACTIVE));
|
||||||
|
}
|
||||||
|
|
||||||
|
$columns = $column_query->execute();
|
||||||
|
$columns = mpull($columns, null, 'getSequence');
|
||||||
|
ksort($columns);
|
||||||
|
|
||||||
|
return $columns;
|
||||||
|
}
|
||||||
|
|
||||||
private function buildSortMenu(
|
private function buildSortMenu(
|
||||||
PhabricatorUser $viewer,
|
PhabricatorUser $viewer,
|
||||||
$sort_key) {
|
$sort_key) {
|
||||||
|
@ -697,46 +700,6 @@ final class PhabricatorProjectBoardViewController
|
||||||
return $column_button;
|
return $column_button;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function initializeWorkboardDialog(PhabricatorProject $project) {
|
|
||||||
|
|
||||||
$instructions = pht('This workboard has not been setup yet.');
|
|
||||||
$new_selector = id(new AphrontFormRadioButtonControl())
|
|
||||||
->setName('initialize-type')
|
|
||||||
->setValue('backlog-only')
|
|
||||||
->addButton(
|
|
||||||
'backlog-only',
|
|
||||||
pht('New Empty Board'),
|
|
||||||
pht('Create a new board with just a backlog column.'))
|
|
||||||
->addButton(
|
|
||||||
'import',
|
|
||||||
pht('Import Columns'),
|
|
||||||
pht('Import board columns from another project.'));
|
|
||||||
|
|
||||||
|
|
||||||
$cancel_uri = $this->getApplicationURI('profile/'.$project->getID().'/');
|
|
||||||
|
|
||||||
return $this->newDialog()
|
|
||||||
->setTitle(pht('New Workboard'))
|
|
||||||
->addSubmitButton('Continue')
|
|
||||||
->addCancelButton($cancel_uri)
|
|
||||||
->appendParagraph($instructions)
|
|
||||||
->appendChild($new_selector);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function noAccessDialog(PhabricatorProject $project) {
|
|
||||||
|
|
||||||
$instructions = pht('This workboard has not been setup yet.');
|
|
||||||
|
|
||||||
$dialog = id(new AphrontDialogView())
|
|
||||||
->setUser($this->getRequest()->getUser())
|
|
||||||
->setTitle(pht('No Workboard'))
|
|
||||||
->addCancelButton($this->getApplicationURI('view/'.$project->getID().'/'))
|
|
||||||
->appendParagraph($instructions);
|
|
||||||
|
|
||||||
return id(new AphrontDialogResponse())
|
|
||||||
->setDialog($dialog);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add current state parameters (like order and the visibility of hidden
|
* Add current state parameters (like order and the visibility of hidden
|
||||||
|
@ -785,4 +748,78 @@ final class PhabricatorProjectBoardViewController
|
||||||
return $create_uri;
|
return $create_uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private function buildInitializeContent(PhabricatorProject $project) {
|
||||||
|
$request = $this->getRequest();
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
$type = $request->getStr('initialize-type');
|
||||||
|
|
||||||
|
$id = $project->getID();
|
||||||
|
|
||||||
|
$profile_uri = $this->getApplicationURI("profile/{$id}/");
|
||||||
|
$board_uri = $this->getApplicationURI("board/{$id}/");
|
||||||
|
$import_uri = $this->getApplicationURI("board/{$id}/import/");
|
||||||
|
|
||||||
|
switch ($type) {
|
||||||
|
case 'backlog-only':
|
||||||
|
$column = PhabricatorProjectColumn::initializeNewColumn($viewer)
|
||||||
|
->setSequence(0)
|
||||||
|
->setProperty('isDefault', true)
|
||||||
|
->setProjectPHID($project->getPHID())
|
||||||
|
->save();
|
||||||
|
|
||||||
|
return id(new AphrontRedirectResponse())
|
||||||
|
->setURI($board_uri);
|
||||||
|
case 'import':
|
||||||
|
return id(new AphrontRedirectResponse())
|
||||||
|
->setURI($import_uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
$new_selector = id(new AphrontFormRadioButtonControl())
|
||||||
|
->setName('initialize-type')
|
||||||
|
->setValue('backlog-only')
|
||||||
|
->addButton(
|
||||||
|
'backlog-only',
|
||||||
|
pht('New Empty Board'),
|
||||||
|
pht('Create a new board with just a backlog column.'))
|
||||||
|
->addButton(
|
||||||
|
'import',
|
||||||
|
pht('Import Columns'),
|
||||||
|
pht('Import board columns from another project.'));
|
||||||
|
|
||||||
|
$form = id(new AphrontFormView())
|
||||||
|
->setUser($viewer)
|
||||||
|
->appendRemarkupInstructions(
|
||||||
|
pht('The workboard for this project has not been created yet.'))
|
||||||
|
->appendControl($new_selector)
|
||||||
|
->appendControl(
|
||||||
|
id(new AphrontFormSubmitControl())
|
||||||
|
->addCancelButton($profile_uri)
|
||||||
|
->setValue(pht('Create Workboard')));
|
||||||
|
|
||||||
|
$box = id(new PHUIObjectBoxView())
|
||||||
|
->setHeaderText(pht('Create Workboard'))
|
||||||
|
->setForm($form);
|
||||||
|
|
||||||
|
return $box;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function buildNoAccessContent(PhabricatorProject $project) {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
$id = $project->getID();
|
||||||
|
|
||||||
|
$profile_uri = $this->getApplicationURI("profile/{$id}/");
|
||||||
|
|
||||||
|
return $this->newDialog()
|
||||||
|
->setTitle(pht('Unable to Create Workboard'))
|
||||||
|
->appendParagraph(
|
||||||
|
pht(
|
||||||
|
'The workboard for this project has not been created yet, '.
|
||||||
|
'but you do not have permission to create it. Only users '.
|
||||||
|
'who can edit this project can create a workboard for it.'))
|
||||||
|
->addCancelButton($profile_uri);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue