From cb605ad5eee2a0e01bbd8d06dec519f3f1dddb70 Mon Sep 17 00:00:00 2001 From: epriestley Date: Mon, 3 Feb 2014 10:52:15 -0800 Subject: [PATCH] Add edit/view plumbing for dashboards and panels Summary: Ref T3583. This doesn't add any dashboard/panel-specific code beyond headers/titles/buttons/etc., but allows you to create and view dashboards and panel skeletons. Test Plan: See screenshots. Reviewers: btrahan, chad Reviewed By: btrahan CC: aran Maniphest Tasks: T3583 Differential Revision: https://secure.phabricator.com/D8131 --- .../20140130.dash.3.boardxaction.sql | 21 +++ .../20140130.dash.4.panelxaction.sql | 21 +++ src/__phutil_library_map__.php | 26 +++- .../PhabricatorApplicationDashboard.php | 7 +- .../PhabricatorDashboardEditController.php | 119 +++++++++++++++++ .../PhabricatorDashboardListController.php | 29 ++++- ...habricatorDashboardPanelEditController.php | 123 ++++++++++++++++++ ...habricatorDashboardPanelListController.php | 30 ++++- ...habricatorDashboardPanelViewController.php | 123 ++++++++++++++++++ .../PhabricatorDashboardViewController.php | 120 +++++++++++++++++ ...ricatorDashboardPanelTransactionEditor.php | 101 ++++++++++++++ .../PhabricatorDashboardTransactionEditor.php | 101 ++++++++++++++ ...bricatorDashboardPanelTransactionQuery.php | 10 ++ .../PhabricatorDashboardTransactionQuery.php | 10 ++ .../storage/PhabricatorDashboard.php | 13 +- .../storage/PhabricatorDashboardPanel.php | 21 ++- .../PhabricatorDashboardPanelTransaction.php | 89 +++++++++++++ .../PhabricatorDashboardTransaction.php | 89 +++++++++++++ 18 files changed, 1040 insertions(+), 13 deletions(-) create mode 100644 resources/sql/autopatches/20140130.dash.3.boardxaction.sql create mode 100644 resources/sql/autopatches/20140130.dash.4.panelxaction.sql create mode 100644 src/applications/dashboard/controller/PhabricatorDashboardEditController.php create mode 100644 src/applications/dashboard/controller/PhabricatorDashboardPanelEditController.php create mode 100644 src/applications/dashboard/controller/PhabricatorDashboardPanelViewController.php create mode 100644 src/applications/dashboard/controller/PhabricatorDashboardViewController.php create mode 100644 src/applications/dashboard/editor/PhabricatorDashboardPanelTransactionEditor.php create mode 100644 src/applications/dashboard/editor/PhabricatorDashboardTransactionEditor.php create mode 100644 src/applications/dashboard/query/PhabricatorDashboardPanelTransactionQuery.php create mode 100644 src/applications/dashboard/query/PhabricatorDashboardTransactionQuery.php create mode 100644 src/applications/dashboard/storage/PhabricatorDashboardPanelTransaction.php create mode 100644 src/applications/dashboard/storage/PhabricatorDashboardTransaction.php diff --git a/resources/sql/autopatches/20140130.dash.3.boardxaction.sql b/resources/sql/autopatches/20140130.dash.3.boardxaction.sql new file mode 100644 index 0000000000..a29a4f0e1b --- /dev/null +++ b/resources/sql/autopatches/20140130.dash.3.boardxaction.sql @@ -0,0 +1,21 @@ +CREATE TABLE {$NAMESPACE}_dashboard.dashboard_transaction ( + id INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, + phid VARCHAR(64) NOT NULL COLLATE utf8_bin, + authorPHID VARCHAR(64) NOT NULL COLLATE utf8_bin, + objectPHID VARCHAR(64) NOT NULL COLLATE utf8_bin, + viewPolicy VARCHAR(64) NOT NULL COLLATE utf8_bin, + editPolicy VARCHAR(64) NOT NULL COLLATE utf8_bin, + commentPHID VARCHAR(64) COLLATE utf8_bin, + commentVersion INT UNSIGNED NOT NULL, + transactionType VARCHAR(32) NOT NULL COLLATE utf8_bin, + oldValue LONGTEXT NOT NULL COLLATE utf8_bin, + newValue LONGTEXT NOT NULL COLLATE utf8_bin, + contentSource LONGTEXT NOT NULL COLLATE utf8_bin, + metadata LONGTEXT NOT NULL COLLATE utf8_bin, + dateCreated INT UNSIGNED NOT NULL, + dateModified INT UNSIGNED NOT NULL, + + UNIQUE KEY `key_phid` (phid), + KEY `key_object` (objectPHID) + +) ENGINE=InnoDB, COLLATE utf8_general_ci; diff --git a/resources/sql/autopatches/20140130.dash.4.panelxaction.sql b/resources/sql/autopatches/20140130.dash.4.panelxaction.sql new file mode 100644 index 0000000000..cf36381416 --- /dev/null +++ b/resources/sql/autopatches/20140130.dash.4.panelxaction.sql @@ -0,0 +1,21 @@ +CREATE TABLE {$NAMESPACE}_dashboard.dashboard_paneltransaction ( + id INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, + phid VARCHAR(64) NOT NULL COLLATE utf8_bin, + authorPHID VARCHAR(64) NOT NULL COLLATE utf8_bin, + objectPHID VARCHAR(64) NOT NULL COLLATE utf8_bin, + viewPolicy VARCHAR(64) NOT NULL COLLATE utf8_bin, + editPolicy VARCHAR(64) NOT NULL COLLATE utf8_bin, + commentPHID VARCHAR(64) COLLATE utf8_bin, + commentVersion INT UNSIGNED NOT NULL, + transactionType VARCHAR(32) NOT NULL COLLATE utf8_bin, + oldValue LONGTEXT NOT NULL COLLATE utf8_bin, + newValue LONGTEXT NOT NULL COLLATE utf8_bin, + contentSource LONGTEXT NOT NULL COLLATE utf8_bin, + metadata LONGTEXT NOT NULL COLLATE utf8_bin, + dateCreated INT UNSIGNED NOT NULL, + dateModified INT UNSIGNED NOT NULL, + + UNIQUE KEY `key_phid` (phid), + KEY `key_object` (objectPHID) + +) ENGINE=InnoDB, COLLATE utf8_general_ci; diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 9087599749..d345617171 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1390,15 +1390,25 @@ phutil_register_library_map(array( 'PhabricatorDashboard' => 'applications/dashboard/storage/PhabricatorDashboard.php', 'PhabricatorDashboardController' => 'applications/dashboard/controller/PhabricatorDashboardController.php', 'PhabricatorDashboardDAO' => 'applications/dashboard/storage/PhabricatorDashboardDAO.php', + 'PhabricatorDashboardEditController' => 'applications/dashboard/controller/PhabricatorDashboardEditController.php', 'PhabricatorDashboardListController' => 'applications/dashboard/controller/PhabricatorDashboardListController.php', 'PhabricatorDashboardPHIDTypeDashboard' => 'applications/dashboard/phid/PhabricatorDashboardPHIDTypeDashboard.php', 'PhabricatorDashboardPHIDTypePanel' => 'applications/dashboard/phid/PhabricatorDashboardPHIDTypePanel.php', 'PhabricatorDashboardPanel' => 'applications/dashboard/storage/PhabricatorDashboardPanel.php', + 'PhabricatorDashboardPanelEditController' => 'applications/dashboard/controller/PhabricatorDashboardPanelEditController.php', 'PhabricatorDashboardPanelListController' => 'applications/dashboard/controller/PhabricatorDashboardPanelListController.php', 'PhabricatorDashboardPanelQuery' => 'applications/dashboard/query/PhabricatorDashboardPanelQuery.php', 'PhabricatorDashboardPanelSearchEngine' => 'applications/dashboard/query/PhabricatorDashboardPanelSearchEngine.php', + 'PhabricatorDashboardPanelTransaction' => 'applications/dashboard/storage/PhabricatorDashboardPanelTransaction.php', + 'PhabricatorDashboardPanelTransactionEditor' => 'applications/dashboard/editor/PhabricatorDashboardPanelTransactionEditor.php', + 'PhabricatorDashboardPanelTransactionQuery' => 'applications/dashboard/query/PhabricatorDashboardPanelTransactionQuery.php', + 'PhabricatorDashboardPanelViewController' => 'applications/dashboard/controller/PhabricatorDashboardPanelViewController.php', 'PhabricatorDashboardQuery' => 'applications/dashboard/query/PhabricatorDashboardQuery.php', 'PhabricatorDashboardSearchEngine' => 'applications/dashboard/query/PhabricatorDashboardSearchEngine.php', + 'PhabricatorDashboardTransaction' => 'applications/dashboard/storage/PhabricatorDashboardTransaction.php', + 'PhabricatorDashboardTransactionEditor' => 'applications/dashboard/editor/PhabricatorDashboardTransactionEditor.php', + 'PhabricatorDashboardTransactionQuery' => 'applications/dashboard/query/PhabricatorDashboardTransactionQuery.php', + 'PhabricatorDashboardViewController' => 'applications/dashboard/controller/PhabricatorDashboardViewController.php', 'PhabricatorDataNotAttachedException' => 'infrastructure/storage/lisk/PhabricatorDataNotAttachedException.php', 'PhabricatorDebugController' => 'applications/system/PhabricatorDebugController.php', 'PhabricatorDefaultFileStorageEngineSelector' => 'applications/files/engineselector/PhabricatorDefaultFileStorageEngineSelector.php', @@ -4046,6 +4056,7 @@ phutil_register_library_map(array( ), 'PhabricatorDashboardController' => 'PhabricatorController', 'PhabricatorDashboardDAO' => 'PhabricatorLiskDAO', + 'PhabricatorDashboardEditController' => 'PhabricatorDashboardController', 'PhabricatorDashboardListController' => array( 0 => 'PhabricatorDashboardController', @@ -4053,7 +4064,12 @@ phutil_register_library_map(array( ), 'PhabricatorDashboardPHIDTypeDashboard' => 'PhabricatorPHIDType', 'PhabricatorDashboardPHIDTypePanel' => 'PhabricatorPHIDType', - 'PhabricatorDashboardPanel' => 'PhabricatorDashboardDAO', + 'PhabricatorDashboardPanel' => + array( + 0 => 'PhabricatorDashboardDAO', + 1 => 'PhabricatorPolicyInterface', + ), + 'PhabricatorDashboardPanelEditController' => 'PhabricatorDashboardController', 'PhabricatorDashboardPanelListController' => array( 0 => 'PhabricatorDashboardController', @@ -4061,8 +4077,16 @@ phutil_register_library_map(array( ), 'PhabricatorDashboardPanelQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorDashboardPanelSearchEngine' => 'PhabricatorApplicationSearchEngine', + 'PhabricatorDashboardPanelTransaction' => 'PhabricatorApplicationTransaction', + 'PhabricatorDashboardPanelTransactionEditor' => 'PhabricatorApplicationTransactionEditor', + 'PhabricatorDashboardPanelTransactionQuery' => 'PhabricatorApplicationTransactionQuery', + 'PhabricatorDashboardPanelViewController' => 'PhabricatorDashboardController', 'PhabricatorDashboardQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorDashboardSearchEngine' => 'PhabricatorApplicationSearchEngine', + 'PhabricatorDashboardTransaction' => 'PhabricatorApplicationTransaction', + 'PhabricatorDashboardTransactionEditor' => 'PhabricatorApplicationTransactionEditor', + 'PhabricatorDashboardTransactionQuery' => 'PhabricatorApplicationTransactionQuery', + 'PhabricatorDashboardViewController' => 'PhabricatorDashboardController', 'PhabricatorDataNotAttachedException' => 'Exception', 'PhabricatorDebugController' => 'PhabricatorController', 'PhabricatorDefaultFileStorageEngineSelector' => 'PhabricatorFileStorageEngineSelector', diff --git a/src/applications/dashboard/application/PhabricatorApplicationDashboard.php b/src/applications/dashboard/application/PhabricatorApplicationDashboard.php index 20f49ef58d..a6654e8951 100644 --- a/src/applications/dashboard/application/PhabricatorApplicationDashboard.php +++ b/src/applications/dashboard/application/PhabricatorApplicationDashboard.php @@ -11,7 +11,7 @@ final class PhabricatorApplicationDashboard extends PhabricatorApplication { } public function getIconName() { - return 'dashboard'; + return 'fancyhome'; } public function getRoutes() { @@ -21,9 +21,14 @@ final class PhabricatorApplicationDashboard extends PhabricatorApplication { '(?:query/(?P[^/]+)/)?' => 'PhabricatorDashboardListController', 'view/(?P\d+)/' => 'PhabricatorDashboardViewController', + 'create/' => 'PhabricatorDashboardEditController', + 'edit/(?:(?P\d+)/)?' => 'PhabricatorDashboardEditController', + 'panel/' => array( '(?:query/(?P[^/]+)/)?' => 'PhabricatorDashboardPanelListController', + 'create/' => 'PhabricatorDashboardPanelEditController', + 'edit/(?:(?P\d+)/)?' => 'PhabricatorDashboardPanelEditController', ), ), ); diff --git a/src/applications/dashboard/controller/PhabricatorDashboardEditController.php b/src/applications/dashboard/controller/PhabricatorDashboardEditController.php new file mode 100644 index 0000000000..cb466256f3 --- /dev/null +++ b/src/applications/dashboard/controller/PhabricatorDashboardEditController.php @@ -0,0 +1,119 @@ +id = idx($data, 'id'); + } + + public function processRequest() { + $request = $this->getRequest(); + $viewer = $request->getUser(); + + if ($this->id) { + $dashboard = id(new PhabricatorDashboardQuery()) + ->setViewer($viewer) + ->withIDs(array($this->id)) + ->requireCapabilities( + array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + )) + ->executeOne(); + if (!$dashboard) { + return new Aphront404Response(); + } + + $is_new = false; + } else { + $dashboard = PhabricatorDashboard::initializeNewDashboard($viewer); + + $is_new = true; + } + + $crumbs = $this->buildApplicationCrumbs(); + + if ($is_new) { + $title = pht('Create Dashboard'); + $header = pht('Create Dashboard'); + $button = pht('Create Dashboard'); + $cancel_uri = $this->getApplicationURI(); + + $crumbs->addTextCrumb('Create Dashboard'); + } else { + $id = $dashboard->getID(); + $cancel_uri = $this->getApplicationURI('view/'.$id.'/'); + + $title = pht('Edit Dashboard %d', $dashboard->getID()); + $header = pht('Edit Dashboard "%s"', $dashboard->getName()); + $button = pht('Save Changes'); + + $crumbs->addTextCrumb(pht('Dashboard %d', $id), $cancel_uri); + $crumbs->addTextCrumb(pht('Edit')); + } + + $v_name = $dashboard->getName(); + $e_name = true; + + $validation_exception = null; + if ($request->isFormPost()) { + $v_name = $request->getStr('name'); + + $xactions = array(); + + $type_name = PhabricatorDashboardTransaction::TYPE_NAME; + + $xactions[] = id(new PhabricatorDashboardTransaction()) + ->setTransactionType($type_name) + ->setNewValue($v_name); + + try { + $editor = id(new PhabricatorDashboardTransactionEditor()) + ->setActor($viewer) + ->setContinueOnNoEffect(true) + ->setContentSourceFromRequest($request) + ->applyTransactions($dashboard, $xactions); + + return id(new AphrontRedirectResponse()) + ->setURI($this->getApplicationURI('view/'.$dashboard->getID().'/')); + } catch (PhabricatorApplicationTransactionValidationException $ex) { + $validation_exception = $ex; + + $e_name = $validation_exception->getShortMessage($type_name); + } + } + + $form = id(new AphrontFormView()) + ->setUser($viewer) + ->appendChild( + id(new AphrontFormTextControl()) + ->setLabel(pht('Name')) + ->setName('name') + ->setValue($v_name) + ->setError($e_name)) + ->appendChild( + id(new AphrontFormSubmitControl()) + ->setValue($button) + ->addCancelButton($cancel_uri)); + + + $box = id(new PHUIObjectBoxView()) + ->setHeaderText($header) + ->setForm($form) + ->setValidationException($validation_exception); + + return $this->buildApplicationPage( + array( + $crumbs, + $box, + ), + array( + 'title' => $title, + 'device' => true, + )); + } + +} diff --git a/src/applications/dashboard/controller/PhabricatorDashboardListController.php b/src/applications/dashboard/controller/PhabricatorDashboardListController.php index 3d018e5f90..5a25da8a24 100644 --- a/src/applications/dashboard/controller/PhabricatorDashboardListController.php +++ b/src/applications/dashboard/controller/PhabricatorDashboardListController.php @@ -33,11 +33,38 @@ final class PhabricatorDashboardListController return $nav; } + public function buildApplicationCrumbs() { + $crumbs = parent::buildApplicationCrumbs(); + + $crumbs->addAction( + id(new PHUIListItemView()) + ->setIcon('create') + ->setName(pht('Create Dashboard')) + ->setHref($this->getApplicationURI().'create/')); + + return $crumbs; + } + public function renderResultsList( array $dashboards, PhabricatorSavedQuery $query) { + $viewer = $this->getRequest()->getUser(); - return 'got '.count($dashboards).' ok'; + $list = new PHUIObjectItemListView(); + $list->setUser($viewer); + foreach ($dashboards as $dashboard) { + $id = $dashboard->getID(); + + $item = id(new PHUIObjectItemView()) + ->setObjectName(pht('Dashboard %d', $id)) + ->setHeader($dashboard->getName()) + ->setHref($this->getApplicationURI("view/{$id}/")) + ->setObject($dashboard); + + $list->addItem($item); + } + + return $list; } } diff --git a/src/applications/dashboard/controller/PhabricatorDashboardPanelEditController.php b/src/applications/dashboard/controller/PhabricatorDashboardPanelEditController.php new file mode 100644 index 0000000000..04c74da79f --- /dev/null +++ b/src/applications/dashboard/controller/PhabricatorDashboardPanelEditController.php @@ -0,0 +1,123 @@ +id = idx($data, 'id'); + } + + public function processRequest() { + $request = $this->getRequest(); + $viewer = $request->getUser(); + + if ($this->id) { + $is_create = false; + + $panel = id(new PhabricatorDashboardPanelQuery()) + ->setViewer($viewer) + ->withIDs(array($this->id)) + ->requireCapabilities( + array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + )) + ->executeOne(); + if (!$panel) { + return new Aphront404Response(); + } + + } else { + $is_create = true; + + $panel = PhabricatorDashboardPanel::initializeNewPanel($viewer); + } + + if ($is_create) { + $title = pht('New Panel'); + $header = pht('Create New Panel'); + $button = pht('Create Panel'); + $cancel_uri = $this->getApplicationURI('panel/'); + } else { + $title = pht('Edit %s', $panel->getMonogram()); + $header = pht('Edit %s %s', $panel->getMonogram(), $panel->getName()); + $button = pht('Save Panel'); + $cancel_uri = '/'.$panel->getMonogram(); + } + + $v_name = $panel->getName(); + $e_name = true; + + $validation_exception = null; + if ($request->isFormPost()) { + $v_name = $request->getStr('name'); + + $xactions = array(); + + $type_name = PhabricatorDashboardPanelTransaction::TYPE_NAME; + + $xactions[] = id(new PhabricatorDashboardPanelTransaction()) + ->setTransactionType($type_name) + ->setNewValue($v_name); + + try { + $editor = id(new PhabricatorDashboardPanelTransactionEditor()) + ->setActor($viewer) + ->setContinueOnNoEffect(true) + ->setContentSourceFromRequest($request) + ->applyTransactions($panel, $xactions); + + return id(new AphrontRedirectResponse()) + ->setURI('/'.$panel->getMonogram()); + } catch (PhabricatorApplicationTransactionValidationException $ex) { + $validation_exception = $ex; + + $e_name = $validation_exception->getShortMessage($type_name); + } + } + + $form = id(new AphrontFormView()) + ->setUser($viewer) + ->appendChild( + id(new AphrontFormTextControl()) + ->setLabel(pht('Name')) + ->setName('name') + ->setValue($v_name) + ->setError($e_name)) + ->appendChild( + id(new AphrontFormSubmitControl()) + ->setValue($button) + ->addCancelButton($cancel_uri)); + + $crumbs = $this->buildApplicationCrumbs(); + $crumbs->addTextCrumb( + pht('Panels'), + $this->getApplicationURI('panel/')); + if ($is_create) { + $crumbs->addTextCrumb(pht('New Panel')); + } else { + $crumbs->addTextCrumb( + $panel->getMonogram(), + '/'.$panel->getMonogram()); + $crumbs->addTextCrumb(pht('Edit')); + } + + $box = id(new PHUIObjectBoxView()) + ->setHeaderText($header) + ->setValidationException($validation_exception) + ->setForm($form); + + return $this->buildApplicationPage( + array( + $crumbs, + $box, + ), + array( + 'title' => $title, + 'device' => true, + )); + } + +} diff --git a/src/applications/dashboard/controller/PhabricatorDashboardPanelListController.php b/src/applications/dashboard/controller/PhabricatorDashboardPanelListController.php index d4531d8ab8..d2cd894495 100644 --- a/src/applications/dashboard/controller/PhabricatorDashboardPanelListController.php +++ b/src/applications/dashboard/controller/PhabricatorDashboardPanelListController.php @@ -33,11 +33,39 @@ final class PhabricatorDashboardPanelListController return $nav; } + public function buildApplicationCrumbs() { + $crumbs = parent::buildApplicationCrumbs(); + + $crumbs->addTextCrumb(pht('Panels'), $this->getApplicationURI().'panel/'); + + $crumbs->addAction( + id(new PHUIListItemView()) + ->setIcon('create') + ->setName(pht('Create Panel')) + ->setHref($this->getApplicationURI().'panel/create/')); + + return $crumbs; + } + public function renderResultsList( array $panels, PhabricatorSavedQuery $query) { - return 'got '.count($panels).' ok'; + $viewer = $this->getRequest()->getUser(); + + $list = new PHUIObjectItemListView(); + $list->setUser($viewer); + foreach ($panels as $panel) { + $item = id(new PHUIObjectItemView()) + ->setObjectName($panel->getMonogram()) + ->setHeader($panel->getName()) + ->setHref('/'.$panel->getMonogram()) + ->setObject($panel); + + $list->addItem($item); + } + + return $list; } } diff --git a/src/applications/dashboard/controller/PhabricatorDashboardPanelViewController.php b/src/applications/dashboard/controller/PhabricatorDashboardPanelViewController.php new file mode 100644 index 0000000000..5d357d862d --- /dev/null +++ b/src/applications/dashboard/controller/PhabricatorDashboardPanelViewController.php @@ -0,0 +1,123 @@ +id = $data['id']; + } + + public function processRequest() { + $request = $this->getRequest(); + $viewer = $request->getUser(); + + $panel = id(new PhabricatorDashboardPanelQuery()) + ->setViewer($viewer) + ->withIDs(array($this->id)) + ->executeOne(); + if (!$panel) { + return new Aphront404Response(); + } + + $title = $panel->getMonogram().' '.$panel->getName(); + $crumbs = $this->buildApplicationCrumbs(); + $crumbs->addTextCrumb( + pht('Panels'), + $this->getApplicationURI('panel/')); + $crumbs->addTextCrumb($panel->getMonogram()); + + $header = $this->buildHeaderView($panel); + $actions = $this->buildActionView($panel); + $properties = $this->buildPropertyView($panel); + $timeline = $this->buildTransactions($panel); + + $properties->setActionList($actions); + $box = id(new PHUIObjectBoxView()) + ->setHeader($header) + ->addPropertyList($properties); + + return $this->buildApplicationPage( + array( + $crumbs, + $box, + $timeline, + ), + array( + 'title' => $title, + 'device' => true, + )); + } + + private function buildHeaderView(PhabricatorDashboardPanel $panel) { + $viewer = $this->getRequest()->getUser(); + + return id(new PHUIHeaderView()) + ->setUser($viewer) + ->setHeader($panel->getName()) + ->setPolicyObject($panel); + } + + private function buildActionView(PhabricatorDashboardPanel $panel) { + $viewer = $this->getRequest()->getUser(); + $id = $panel->getID(); + + $actions = id(new PhabricatorActionListView()) + ->setObjectURI('/'.$panel->getMonogram()) + ->setUser($viewer); + + $can_edit = PhabricatorPolicyFilter::hasCapability( + $viewer, + $panel, + PhabricatorPolicyCapability::CAN_EDIT); + + $actions->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Edit Panel')) + ->setIcon('edit') + ->setHref($this->getApplicationURI("panel/edit/{$id}/")) + ->setDisabled(!$can_edit) + ->setWorkflow(!$can_edit)); + + return $actions; + } + + private function buildPropertyView(PhabricatorDashboardPanel $panel) { + $viewer = $this->getRequest()->getUser(); + + $properties = id(new PHUIPropertyListView()) + ->setUser($viewer) + ->setObject($panel); + + $descriptions = PhabricatorPolicyQuery::renderPolicyDescriptions( + $viewer, + $panel); + + $properties->addProperty( + pht('Editable By'), + $descriptions[PhabricatorPolicyCapability::CAN_EDIT]); + + return $properties; + } + + private function buildTransactions(PhabricatorDashboardPanel $panel) { + $viewer = $this->getRequest()->getUser(); + + $xactions = id(new PhabricatorDashboardPanelTransactionQuery()) + ->setViewer($viewer) + ->withObjectPHIDs(array($panel->getPHID())) + ->execute(); + + $engine = id(new PhabricatorMarkupEngine()) + ->setViewer($viewer); + + $timeline = id(new PhabricatorApplicationTransactionView()) + ->setUser($viewer) + ->setObjectPHID($panel->getPHID()) + ->setTransactions($xactions); + + return $timeline; + } + +} diff --git a/src/applications/dashboard/controller/PhabricatorDashboardViewController.php b/src/applications/dashboard/controller/PhabricatorDashboardViewController.php new file mode 100644 index 0000000000..acd3c03768 --- /dev/null +++ b/src/applications/dashboard/controller/PhabricatorDashboardViewController.php @@ -0,0 +1,120 @@ +id = $data['id']; + } + + public function processRequest() { + $request = $this->getRequest(); + $viewer = $request->getUser(); + + $dashboard = id(new PhabricatorDashboardQuery()) + ->setViewer($viewer) + ->withIDs(array($this->id)) + ->executeOne(); + if (!$dashboard) { + return new Aphront404Response(); + } + + $title = $dashboard->getName(); + $crumbs = $this->buildApplicationCrumbs(); + $crumbs->addTextCrumb(pht('Dashboard %d', $dashboard->getID())); + + $header = $this->buildHeaderView($dashboard); + $actions = $this->buildActionView($dashboard); + $properties = $this->buildPropertyView($dashboard); + $timeline = $this->buildTransactions($dashboard); + + $properties->setActionList($actions); + $box = id(new PHUIObjectBoxView()) + ->setHeader($header) + ->addPropertyList($properties); + + return $this->buildApplicationPage( + array( + $crumbs, + $box, + $timeline, + ), + array( + 'title' => $title, + 'device' => true, + )); + } + + private function buildHeaderView(PhabricatorDashboard $dashboard) { + $viewer = $this->getRequest()->getUser(); + + return id(new PHUIHeaderView()) + ->setUser($viewer) + ->setHeader($dashboard->getName()) + ->setPolicyObject($dashboard); + } + + private function buildActionView(PhabricatorDashboard $dashboard) { + $viewer = $this->getRequest()->getUser(); + $id = $dashboard->getID(); + + $actions = id(new PhabricatorActionListView()) + ->setObjectURI($this->getApplicationURI('view/'.$dashboard->getID().'/')) + ->setUser($viewer); + + $can_edit = PhabricatorPolicyFilter::hasCapability( + $viewer, + $dashboard, + PhabricatorPolicyCapability::CAN_EDIT); + + $actions->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Edit Dashboard')) + ->setIcon('edit') + ->setHref($this->getApplicationURI("edit/{$id}/")) + ->setDisabled(!$can_edit) + ->setWorkflow(!$can_edit)); + + return $actions; + } + + private function buildPropertyView(PhabricatorDashboard $dashboard) { + $viewer = $this->getRequest()->getUser(); + + $properties = id(new PHUIPropertyListView()) + ->setUser($viewer) + ->setObject($dashboard); + + $descriptions = PhabricatorPolicyQuery::renderPolicyDescriptions( + $viewer, + $dashboard); + + $properties->addProperty( + pht('Editable By'), + $descriptions[PhabricatorPolicyCapability::CAN_EDIT]); + + return $properties; + } + + private function buildTransactions(PhabricatorDashboard $dashboard) { + $viewer = $this->getRequest()->getUser(); + + $xactions = id(new PhabricatorDashboardTransactionQuery()) + ->setViewer($viewer) + ->withObjectPHIDs(array($dashboard->getPHID())) + ->execute(); + + $engine = id(new PhabricatorMarkupEngine()) + ->setViewer($viewer); + + $timeline = id(new PhabricatorApplicationTransactionView()) + ->setUser($viewer) + ->setObjectPHID($dashboard->getPHID()) + ->setTransactions($xactions); + + return $timeline; + } + +} diff --git a/src/applications/dashboard/editor/PhabricatorDashboardPanelTransactionEditor.php b/src/applications/dashboard/editor/PhabricatorDashboardPanelTransactionEditor.php new file mode 100644 index 0000000000..19dc8da69e --- /dev/null +++ b/src/applications/dashboard/editor/PhabricatorDashboardPanelTransactionEditor.php @@ -0,0 +1,101 @@ +getTransactionType()) { + case PhabricatorDashboardPanelTransaction::TYPE_NAME: + if ($this->getIsNewObject()) { + return null; + } + return $object->getName(); + } + + return parent::getCustomTransactionOldValue($object, $xaction); + } + + protected function getCustomTransactionNewValue( + PhabricatorLiskDAO $object, + PhabricatorApplicationTransaction $xaction) { + switch ($xaction->getTransactionType()) { + case PhabricatorDashboardPanelTransaction::TYPE_NAME: + return $xaction->getNewValue(); + } + return parent::getCustomTransactionNewValue($object, $xaction); + } + + protected function applyCustomInternalTransaction( + PhabricatorLiskDAO $object, + PhabricatorApplicationTransaction $xaction) { + switch ($xaction->getTransactionType()) { + case PhabricatorDashboardPanelTransaction::TYPE_NAME: + $object->setName($xaction->getNewValue()); + return; + case PhabricatorTransactions::TYPE_VIEW_POLICY: + $object->setViewPolicy($xaction->getNewValue()); + return; + case PhabricatorTransactions::TYPE_EDIT_POLICY: + $object->setEditPolicy($xaction->getNewValue()); + return; + } + + return parent::applyCustomInternalTransaction($object, $xaction); + } + + protected function applyCustomExternalTransaction( + PhabricatorLiskDAO $object, + PhabricatorApplicationTransaction $xaction) { + + switch ($xaction->getTransactionType()) { + case PhabricatorDashboardPanelTransaction::TYPE_NAME: + return; + } + + return parent::applyCustomExternalTransaction($object, $xaction); + } + + protected function validateTransaction( + PhabricatorLiskDAO $object, + $type, + array $xactions) { + + $errors = parent::validateTransaction($object, $type, $xactions); + + switch ($type) { + case PhabricatorDashboardPanelTransaction::TYPE_NAME: + $missing = $this->validateIsEmptyTextField( + $object->getName(), + $xactions); + + if ($missing) { + $error = new PhabricatorApplicationTransactionValidationError( + $type, + pht('Required'), + pht('Panel name is required.'), + nonempty(last($xactions), null)); + + $error->setIsMissingFieldError(true); + $errors[] = $error; + } + break; + } + + return $errors; + } + + +} diff --git a/src/applications/dashboard/editor/PhabricatorDashboardTransactionEditor.php b/src/applications/dashboard/editor/PhabricatorDashboardTransactionEditor.php new file mode 100644 index 0000000000..023dd704f2 --- /dev/null +++ b/src/applications/dashboard/editor/PhabricatorDashboardTransactionEditor.php @@ -0,0 +1,101 @@ +getTransactionType()) { + case PhabricatorDashboardTransaction::TYPE_NAME: + if ($this->getIsNewObject()) { + return null; + } + return $object->getName(); + } + + return parent::getCustomTransactionOldValue($object, $xaction); + } + + protected function getCustomTransactionNewValue( + PhabricatorLiskDAO $object, + PhabricatorApplicationTransaction $xaction) { + switch ($xaction->getTransactionType()) { + case PhabricatorDashboardTransaction::TYPE_NAME: + return $xaction->getNewValue(); + } + return parent::getCustomTransactionNewValue($object, $xaction); + } + + protected function applyCustomInternalTransaction( + PhabricatorLiskDAO $object, + PhabricatorApplicationTransaction $xaction) { + switch ($xaction->getTransactionType()) { + case PhabricatorDashboardTransaction::TYPE_NAME: + $object->setName($xaction->getNewValue()); + return; + case PhabricatorTransactions::TYPE_VIEW_POLICY: + $object->setViewPolicy($xaction->getNewValue()); + return; + case PhabricatorTransactions::TYPE_EDIT_POLICY: + $object->setEditPolicy($xaction->getNewValue()); + return; + } + + return parent::applyCustomInternalTransaction($object, $xaction); + } + + protected function applyCustomExternalTransaction( + PhabricatorLiskDAO $object, + PhabricatorApplicationTransaction $xaction) { + + switch ($xaction->getTransactionType()) { + case PhabricatorDashboardTransaction::TYPE_NAME: + return; + } + + return parent::applyCustomExternalTransaction($object, $xaction); + } + + protected function validateTransaction( + PhabricatorLiskDAO $object, + $type, + array $xactions) { + + $errors = parent::validateTransaction($object, $type, $xactions); + + switch ($type) { + case PhabricatorDashboardTransaction::TYPE_NAME: + $missing = $this->validateIsEmptyTextField( + $object->getName(), + $xactions); + + if ($missing) { + $error = new PhabricatorApplicationTransactionValidationError( + $type, + pht('Required'), + pht('Dashboard name is required.'), + nonempty(last($xactions), null)); + + $error->setIsMissingFieldError(true); + $errors[] = $error; + } + break; + } + + return $errors; + } + + +} diff --git a/src/applications/dashboard/query/PhabricatorDashboardPanelTransactionQuery.php b/src/applications/dashboard/query/PhabricatorDashboardPanelTransactionQuery.php new file mode 100644 index 0000000000..9a192485c1 --- /dev/null +++ b/src/applications/dashboard/query/PhabricatorDashboardPanelTransactionQuery.php @@ -0,0 +1,10 @@ +setName('') + ->setViewPolicy(PhabricatorPolicies::POLICY_USER) + ->setEditPolicy($actor->getPHID()); + } public function getConfiguration() { return array( diff --git a/src/applications/dashboard/storage/PhabricatorDashboardPanel.php b/src/applications/dashboard/storage/PhabricatorDashboardPanel.php index 9ef06e2a37..0e112bc291 100644 --- a/src/applications/dashboard/storage/PhabricatorDashboardPanel.php +++ b/src/applications/dashboard/storage/PhabricatorDashboardPanel.php @@ -3,12 +3,21 @@ /** * An individual dashboard panel. */ -final class PhabricatorDashboardPanel extends PhabricatorDashboardDAO { +final class PhabricatorDashboardPanel + extends PhabricatorDashboardDAO + implements PhabricatorPolicyInterface { - private $name; - private $viewPolicy; - private $editPolicy; - private $properties = array(); + protected $name; + protected $viewPolicy; + protected $editPolicy; + protected $properties = array(); + + public static function initializeNewPanel(PhabricatorUser $actor) { + return id(new PhabricatorDashboardPanel()) + ->setName('') + ->setViewPolicy(PhabricatorPolicies::POLICY_USER) + ->setEditPolicy($actor->getPHID()); + } public function getConfiguration() { return array( @@ -21,7 +30,7 @@ final class PhabricatorDashboardPanel extends PhabricatorDashboardDAO { public function generatePHID() { return PhabricatorPHID::generateNewPHID( - PhabricatorDashboardPHIDTypeDashboard::TYPECONST); + PhabricatorDashboardPHIDTypePanel::TYPECONST); } public function getProperty($key, $default = null) { diff --git a/src/applications/dashboard/storage/PhabricatorDashboardPanelTransaction.php b/src/applications/dashboard/storage/PhabricatorDashboardPanelTransaction.php new file mode 100644 index 0000000000..7169081e0d --- /dev/null +++ b/src/applications/dashboard/storage/PhabricatorDashboardPanelTransaction.php @@ -0,0 +1,89 @@ +getAuthorPHID(); + $object_phid = $this->getObjectPHID(); + + $old = $this->getOldValue(); + $new = $this->getNewValue(); + + $author_link = $this->renderHandleLink($author_phid); + + $type = $this->getTransactionType(); + switch ($type) { + case self::TYPE_NAME: + if (!strlen($old)) { + return pht( + '%s created this panel.', + $author_link); + } else { + return pht( + '%s renamed this panel from "%s" to "%s".', + $author_link, + $old, + $new); + } + } + + return parent::getTitle(); + } + + public function getTitleForFeed(PhabricatorFeedStory $story) { + $author_phid = $this->getAuthorPHID(); + $object_phid = $this->getObjectPHID(); + + $old = $this->getOldValue(); + $new = $this->getNewValue(); + + $author_link = $this->renderHandleLink($author_phid); + $object_link = $this->renderHandleLink($object_phid); + + $type = $this->getTransactionType(); + switch ($type) { + case self::TYPE_NAME: + if (!strlen($old)) { + return pht( + '%s created dashboard panel %s.', + $author_link, + $object_link); + } else { + return pht( + '%s renamed dashboard panel %s from "%s" to "%s".', + $author_link, + $object_link, + $old, + $new); + } + } + + return parent::getTitleForFeed($story); + } + + public function getColor() { + $old = $this->getOldValue(); + $new = $this->getNewValue(); + + switch ($this->getTransactionType()) { + case self::TYPE_NAME: + if (!strlen($old)) { + return PhabricatorTransactions::COLOR_GREEN; + } + break; + } + + return parent::getColor(); + } +} diff --git a/src/applications/dashboard/storage/PhabricatorDashboardTransaction.php b/src/applications/dashboard/storage/PhabricatorDashboardTransaction.php new file mode 100644 index 0000000000..8e6e8f4580 --- /dev/null +++ b/src/applications/dashboard/storage/PhabricatorDashboardTransaction.php @@ -0,0 +1,89 @@ +getAuthorPHID(); + $object_phid = $this->getObjectPHID(); + + $old = $this->getOldValue(); + $new = $this->getNewValue(); + + $author_link = $this->renderHandleLink($author_phid); + + $type = $this->getTransactionType(); + switch ($type) { + case self::TYPE_NAME: + if (!strlen($old)) { + return pht( + '%s created this dashboard.', + $author_link); + } else { + return pht( + '%s renamed this dashboard from "%s" to "%s".', + $author_link, + $old, + $new); + } + } + + return parent::getTitle(); + } + + public function getTitleForFeed(PhabricatorFeedStory $story) { + $author_phid = $this->getAuthorPHID(); + $object_phid = $this->getObjectPHID(); + + $old = $this->getOldValue(); + $new = $this->getNewValue(); + + $author_link = $this->renderHandleLink($author_phid); + $object_link = $this->renderHandleLink($object_phid); + + $type = $this->getTransactionType(); + switch ($type) { + case self::TYPE_NAME: + if (!strlen($old)) { + return pht( + '%s created dashboard %s.', + $author_link, + $object_link); + } else { + return pht( + '%s renamed dashboard %s from "%s" to "%s".', + $author_link, + $object_link, + $old, + $new); + } + } + + return parent::getTitleForFeed($story); + } + + public function getColor() { + $old = $this->getOldValue(); + $new = $this->getNewValue(); + + switch ($this->getTransactionType()) { + case self::TYPE_NAME: + if (!strlen($old)) { + return PhabricatorTransactions::COLOR_GREEN; + } + break; + } + + return parent::getColor(); + } +}