Page MenuHomePhabricator

D20379.id48657.diff
No OneTemporary

D20379.id48657.diff

diff --git a/resources/celerity/map.php b/resources/celerity/map.php
--- a/resources/celerity/map.php
+++ b/resources/celerity/map.php
@@ -9,8 +9,8 @@
'names' => array(
'conpherence.pkg.css' => '3c8a0668',
'conpherence.pkg.js' => '020aebcf',
- 'core.pkg.css' => 'a1c2d49b',
- 'core.pkg.js' => 'a568e834',
+ 'core.pkg.css' => 'dacb981b',
+ 'core.pkg.js' => 'c783d8f6',
'differential.pkg.css' => '8d8360fb',
'differential.pkg.js' => '67e02996',
'diffusion.pkg.css' => '42c75c37',
@@ -37,7 +37,7 @@
'rsrc/css/aphront/typeahead.css' => '8779483d',
'rsrc/css/application/almanac/almanac.css' => '2e050f4f',
'rsrc/css/application/auth/auth.css' => 'add92fd8',
- 'rsrc/css/application/base/main-menu-view.css' => '8e2d9a28',
+ 'rsrc/css/application/base/main-menu-view.css' => '17b71bbc',
'rsrc/css/application/base/notification-menu.css' => '4df1ee30',
'rsrc/css/application/base/phui-theme.css' => '35883b37',
'rsrc/css/application/base/standard-page-view.css' => '8a295cb9',
@@ -58,7 +58,7 @@
'rsrc/css/application/contentsource/content-source-view.css' => 'cdf0d579',
'rsrc/css/application/countdown/timer.css' => 'bff8012f',
'rsrc/css/application/daemon/bulk-job.css' => '73af99f5',
- 'rsrc/css/application/dashboard/dashboard.css' => '4267d6c6',
+ 'rsrc/css/application/dashboard/dashboard.css' => '5a205b9d',
'rsrc/css/application/diff/inline-comment-summary.css' => '81eb368d',
'rsrc/css/application/differential/add-comment.css' => '7e5900d9',
'rsrc/css/application/differential/changeset-view.css' => 'bde53589',
@@ -128,13 +128,13 @@
'rsrc/css/phui/calendar/phui-calendar-list.css' => 'ccd7e4e2',
'rsrc/css/phui/calendar/phui-calendar-month.css' => 'cb758c42',
'rsrc/css/phui/calendar/phui-calendar.css' => 'f11073aa',
- 'rsrc/css/phui/object-item/phui-oi-big-ui.css' => '534f1757',
+ 'rsrc/css/phui/object-item/phui-oi-big-ui.css' => 'fa74cc35',
'rsrc/css/phui/object-item/phui-oi-color.css' => 'b517bfa0',
'rsrc/css/phui/object-item/phui-oi-drag-ui.css' => 'da15d3dc',
'rsrc/css/phui/object-item/phui-oi-flush-ui.css' => '490e2e2e',
'rsrc/css/phui/object-item/phui-oi-list-view.css' => 'f14f2422',
'rsrc/css/phui/object-item/phui-oi-simple-ui.css' => '6a30fa46',
- 'rsrc/css/phui/phui-action-list.css' => 'c4972757',
+ 'rsrc/css/phui/phui-action-list.css' => '8862282e',
'rsrc/css/phui/phui-action-panel.css' => '6c386cbf',
'rsrc/css/phui/phui-badge.css' => '666e25ad',
'rsrc/css/phui/phui-basic-nav-view.css' => '56ebd66d',
@@ -518,7 +518,7 @@
'rsrc/js/phuix/PHUIXActionView.js' => 'aaa08f3b',
'rsrc/js/phuix/PHUIXAutocomplete.js' => '2fbe234d',
'rsrc/js/phuix/PHUIXButtonView.js' => '55a24e84',
- 'rsrc/js/phuix/PHUIXDropdownMenu.js' => 'bdce4d78',
+ 'rsrc/js/phuix/PHUIXDropdownMenu.js' => '7acfd98b',
'rsrc/js/phuix/PHUIXExample.js' => 'c2c500a7',
'rsrc/js/phuix/PHUIXFormControl.js' => '38c1f3fb',
'rsrc/js/phuix/PHUIXIconView.js' => 'a5257c4e',
@@ -757,7 +757,7 @@
'path-typeahead' => 'ad486db3',
'people-picture-menu-item-css' => 'fe8e07cf',
'people-profile-css' => '2ea2daa1',
- 'phabricator-action-list-view-css' => 'c4972757',
+ 'phabricator-action-list-view-css' => '8862282e',
'phabricator-busy' => '5202e831',
'phabricator-chatlog-css' => 'abdc76ee',
'phabricator-content-source-view-css' => 'cdf0d579',
@@ -765,7 +765,7 @@
'phabricator-countdown-css' => 'bff8012f',
'phabricator-darklog' => '3b869402',
'phabricator-darkmessage' => '26cd4b73',
- 'phabricator-dashboard-css' => '4267d6c6',
+ 'phabricator-dashboard-css' => '5a205b9d',
'phabricator-diff-changeset' => 'd0a85a85',
'phabricator-diff-changeset-list' => '04023d82',
'phabricator-diff-inline' => 'a4a14a94',
@@ -779,7 +779,7 @@
'phabricator-flag-css' => '2b77be8d',
'phabricator-keyboard-shortcut' => 'c9749dcd',
'phabricator-keyboard-shortcut-manager' => '37b8a04a',
- 'phabricator-main-menu-view' => '8e2d9a28',
+ 'phabricator-main-menu-view' => '17b71bbc',
'phabricator-nav-view-css' => 'f8a0c1bf',
'phabricator-notification' => 'a9b91e3f',
'phabricator-notification-css' => '30240bd2',
@@ -849,7 +849,7 @@
'phui-lightbox-css' => '4ebf22da',
'phui-list-view-css' => '470b1adb',
'phui-object-box-css' => 'f434b6be',
- 'phui-oi-big-ui-css' => '534f1757',
+ 'phui-oi-big-ui-css' => 'fa74cc35',
'phui-oi-color-css' => 'b517bfa0',
'phui-oi-drag-ui-css' => 'da15d3dc',
'phui-oi-flush-ui-css' => '490e2e2e',
@@ -874,7 +874,7 @@
'phuix-action-view' => 'aaa08f3b',
'phuix-autocomplete' => '2fbe234d',
'phuix-button-view' => '55a24e84',
- 'phuix-dropdown-menu' => 'bdce4d78',
+ 'phuix-dropdown-menu' => '7acfd98b',
'phuix-form-control-view' => '38c1f3fb',
'phuix-icon-view' => 'a5257c4e',
'policy-css' => 'ceb56a08',
@@ -1029,6 +1029,9 @@
'javelin-stratcom',
'javelin-util',
),
+ '17b71bbc' => array(
+ 'phui-theme-css',
+ ),
'1b6acc2a' => array(
'javelin-magical-init',
'javelin-util',
@@ -1379,9 +1382,6 @@
'javelin-dom',
'javelin-fx',
),
- '534f1757' => array(
- 'phui-oi-list-view-css',
- ),
'541f81c3' => array(
'javelin-install',
),
@@ -1566,6 +1566,13 @@
'javelin-install',
'javelin-dom',
),
+ '7acfd98b' => array(
+ 'javelin-install',
+ 'javelin-util',
+ 'javelin-dom',
+ 'javelin-vector',
+ 'javelin-stratcom',
+ ),
'7ad020a5' => array(
'javelin-behavior',
'javelin-dom',
@@ -1641,9 +1648,6 @@
'javelin-install',
'javelin-dom',
),
- '8e2d9a28' => array(
- 'phui-theme-css',
- ),
'8f959ad0' => array(
'javelin-behavior',
'javelin-dom',
@@ -1925,13 +1929,6 @@
'javelin-uri',
'phabricator-notification',
),
- 'bdce4d78' => array(
- 'javelin-install',
- 'javelin-util',
- 'javelin-dom',
- 'javelin-vector',
- 'javelin-stratcom',
- ),
'bde53589' => array(
'phui-inline-comment-view-css',
),
@@ -2179,6 +2176,9 @@
'phabricator-keyboard-shortcut',
'conpherence-thread-manager',
),
+ 'fa74cc35' => array(
+ 'phui-oi-list-view-css',
+ ),
'fdc13e4e' => array(
'javelin-install',
),
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -609,6 +609,7 @@
'DifferentialRevisionIDCommitMessageField' => 'applications/differential/field/DifferentialRevisionIDCommitMessageField.php',
'DifferentialRevisionInlineTransaction' => 'applications/differential/xaction/DifferentialRevisionInlineTransaction.php',
'DifferentialRevisionInlinesController' => 'applications/differential/controller/DifferentialRevisionInlinesController.php',
+ 'DifferentialRevisionJIRAIssueURIsHeraldField' => 'applications/differential/herald/DifferentialRevisionJIRAIssueURIsHeraldField.php',
'DifferentialRevisionListController' => 'applications/differential/controller/DifferentialRevisionListController.php',
'DifferentialRevisionListView' => 'applications/differential/view/DifferentialRevisionListView.php',
'DifferentialRevisionMailReceiver' => 'applications/differential/mail/DifferentialRevisionMailReceiver.php',
@@ -2905,54 +2906,58 @@
'PhabricatorDashboard' => 'applications/dashboard/storage/PhabricatorDashboard.php',
'PhabricatorDashboardAddPanelController' => 'applications/dashboard/controller/PhabricatorDashboardAddPanelController.php',
'PhabricatorDashboardApplication' => 'applications/dashboard/application/PhabricatorDashboardApplication.php',
- 'PhabricatorDashboardArchiveController' => 'applications/dashboard/controller/PhabricatorDashboardArchiveController.php',
- 'PhabricatorDashboardArrangeController' => 'applications/dashboard/controller/PhabricatorDashboardArrangeController.php',
+ 'PhabricatorDashboardApplicationInstallWorkflow' => 'applications/dashboard/install/PhabricatorDashboardApplicationInstallWorkflow.php',
+ 'PhabricatorDashboardArchiveController' => 'applications/dashboard/controller/dashboard/PhabricatorDashboardArchiveController.php',
'PhabricatorDashboardConsoleController' => 'applications/dashboard/controller/PhabricatorDashboardConsoleController.php',
'PhabricatorDashboardController' => 'applications/dashboard/controller/PhabricatorDashboardController.php',
'PhabricatorDashboardDAO' => 'applications/dashboard/storage/PhabricatorDashboardDAO.php',
'PhabricatorDashboardDashboardHasPanelEdgeType' => 'applications/dashboard/edge/PhabricatorDashboardDashboardHasPanelEdgeType.php',
'PhabricatorDashboardDashboardPHIDType' => 'applications/dashboard/phid/PhabricatorDashboardDashboardPHIDType.php',
'PhabricatorDashboardDatasource' => 'applications/dashboard/typeahead/PhabricatorDashboardDatasource.php',
- 'PhabricatorDashboardEditController' => 'applications/dashboard/controller/PhabricatorDashboardEditController.php',
+ 'PhabricatorDashboardEditController' => 'applications/dashboard/controller/dashboard/PhabricatorDashboardEditController.php',
+ 'PhabricatorDashboardFavoritesInstallWorkflow' => 'applications/dashboard/install/PhabricatorDashboardFavoritesInstallWorkflow.php',
+ 'PhabricatorDashboardHomeInstallWorkflow' => 'applications/dashboard/install/PhabricatorDashboardHomeInstallWorkflow.php',
'PhabricatorDashboardIconSet' => 'applications/dashboard/icon/PhabricatorDashboardIconSet.php',
'PhabricatorDashboardInstall' => 'applications/dashboard/storage/PhabricatorDashboardInstall.php',
- 'PhabricatorDashboardInstallController' => 'applications/dashboard/controller/PhabricatorDashboardInstallController.php',
+ 'PhabricatorDashboardInstallController' => 'applications/dashboard/controller/dashboard/PhabricatorDashboardInstallController.php',
+ 'PhabricatorDashboardInstallWorkflow' => 'applications/dashboard/install/PhabricatorDashboardInstallWorkflow.php',
'PhabricatorDashboardLayoutConfig' => 'applications/dashboard/layoutconfig/PhabricatorDashboardLayoutConfig.php',
'PhabricatorDashboardListController' => 'applications/dashboard/controller/PhabricatorDashboardListController.php',
- 'PhabricatorDashboardManageController' => 'applications/dashboard/controller/PhabricatorDashboardManageController.php',
'PhabricatorDashboardMovePanelController' => 'applications/dashboard/controller/PhabricatorDashboardMovePanelController.php',
'PhabricatorDashboardNgrams' => 'applications/dashboard/storage/PhabricatorDashboardNgrams.php',
+ 'PhabricatorDashboardObjectInstallWorkflow' => 'applications/dashboard/install/PhabricatorDashboardObjectInstallWorkflow.php',
'PhabricatorDashboardPanel' => 'applications/dashboard/storage/PhabricatorDashboardPanel.php',
- 'PhabricatorDashboardPanelArchiveController' => 'applications/dashboard/controller/PhabricatorDashboardPanelArchiveController.php',
- 'PhabricatorDashboardPanelCoreCustomField' => 'applications/dashboard/customfield/PhabricatorDashboardPanelCoreCustomField.php',
- 'PhabricatorDashboardPanelCustomField' => 'applications/dashboard/customfield/PhabricatorDashboardPanelCustomField.php',
+ 'PhabricatorDashboardPanelArchiveController' => 'applications/dashboard/controller/panel/PhabricatorDashboardPanelArchiveController.php',
'PhabricatorDashboardPanelDatasource' => 'applications/dashboard/typeahead/PhabricatorDashboardPanelDatasource.php',
'PhabricatorDashboardPanelEditConduitAPIMethod' => 'applications/dashboard/conduit/PhabricatorDashboardPanelEditConduitAPIMethod.php',
- 'PhabricatorDashboardPanelEditController' => 'applications/dashboard/controller/PhabricatorDashboardPanelEditController.php',
+ 'PhabricatorDashboardPanelEditController' => 'applications/dashboard/controller/panel/PhabricatorDashboardPanelEditController.php',
'PhabricatorDashboardPanelEditEngine' => 'applications/dashboard/editor/PhabricatorDashboardPanelEditEngine.php',
- 'PhabricatorDashboardPanelEditproController' => 'applications/dashboard/controller/PhabricatorDashboardPanelEditproController.php',
'PhabricatorDashboardPanelHasDashboardEdgeType' => 'applications/dashboard/edge/PhabricatorDashboardPanelHasDashboardEdgeType.php',
- 'PhabricatorDashboardPanelListController' => 'applications/dashboard/controller/PhabricatorDashboardPanelListController.php',
+ 'PhabricatorDashboardPanelListController' => 'applications/dashboard/controller/panel/PhabricatorDashboardPanelListController.php',
+ 'PhabricatorDashboardPanelNameTransaction' => 'applications/dashboard/xaction/panel/PhabricatorDashboardPanelNameTransaction.php',
'PhabricatorDashboardPanelNgrams' => 'applications/dashboard/storage/PhabricatorDashboardPanelNgrams.php',
'PhabricatorDashboardPanelPHIDType' => 'applications/dashboard/phid/PhabricatorDashboardPanelPHIDType.php',
+ 'PhabricatorDashboardPanelPropertyTransaction' => 'applications/dashboard/xaction/panel/PhabricatorDashboardPanelPropertyTransaction.php',
'PhabricatorDashboardPanelQuery' => 'applications/dashboard/query/PhabricatorDashboardPanelQuery.php',
- 'PhabricatorDashboardPanelRenderController' => 'applications/dashboard/controller/PhabricatorDashboardPanelRenderController.php',
+ 'PhabricatorDashboardPanelRenderController' => 'applications/dashboard/controller/panel/PhabricatorDashboardPanelRenderController.php',
'PhabricatorDashboardPanelRenderingEngine' => 'applications/dashboard/engine/PhabricatorDashboardPanelRenderingEngine.php',
- 'PhabricatorDashboardPanelSearchApplicationCustomField' => 'applications/dashboard/customfield/PhabricatorDashboardPanelSearchApplicationCustomField.php',
'PhabricatorDashboardPanelSearchEngine' => 'applications/dashboard/query/PhabricatorDashboardPanelSearchEngine.php',
- 'PhabricatorDashboardPanelSearchQueryCustomField' => 'applications/dashboard/customfield/PhabricatorDashboardPanelSearchQueryCustomField.php',
- 'PhabricatorDashboardPanelTabsCustomField' => 'applications/dashboard/customfield/PhabricatorDashboardPanelTabsCustomField.php',
+ 'PhabricatorDashboardPanelStatusTransaction' => 'applications/dashboard/xaction/panel/PhabricatorDashboardPanelStatusTransaction.php',
+ 'PhabricatorDashboardPanelTabsController' => 'applications/dashboard/controller/panel/PhabricatorDashboardPanelTabsController.php',
'PhabricatorDashboardPanelTransaction' => 'applications/dashboard/storage/PhabricatorDashboardPanelTransaction.php',
'PhabricatorDashboardPanelTransactionEditor' => 'applications/dashboard/editor/PhabricatorDashboardPanelTransactionEditor.php',
'PhabricatorDashboardPanelTransactionQuery' => 'applications/dashboard/query/PhabricatorDashboardPanelTransactionQuery.php',
+ 'PhabricatorDashboardPanelTransactionType' => 'applications/dashboard/xaction/panel/PhabricatorDashboardPanelTransactionType.php',
'PhabricatorDashboardPanelType' => 'applications/dashboard/paneltype/PhabricatorDashboardPanelType.php',
- 'PhabricatorDashboardPanelViewController' => 'applications/dashboard/controller/PhabricatorDashboardPanelViewController.php',
+ 'PhabricatorDashboardPanelViewController' => 'applications/dashboard/controller/panel/PhabricatorDashboardPanelViewController.php',
'PhabricatorDashboardPortal' => 'applications/dashboard/storage/PhabricatorDashboardPortal.php',
'PhabricatorDashboardPortalController' => 'applications/dashboard/controller/portal/PhabricatorDashboardPortalController.php',
+ 'PhabricatorDashboardPortalDatasource' => 'applications/dashboard/typeahead/PhabricatorDashboardPortalDatasource.php',
'PhabricatorDashboardPortalEditConduitAPIMethod' => 'applications/dashboard/conduit/PhabricatorDashboardPortalEditConduitAPIMethod.php',
'PhabricatorDashboardPortalEditController' => 'applications/dashboard/controller/portal/PhabricatorDashboardPortalEditController.php',
'PhabricatorDashboardPortalEditEngine' => 'applications/dashboard/editor/PhabricatorDashboardPortalEditEngine.php',
'PhabricatorDashboardPortalEditor' => 'applications/dashboard/editor/PhabricatorDashboardPortalEditor.php',
+ 'PhabricatorDashboardPortalInstallWorkflow' => 'applications/dashboard/install/PhabricatorDashboardPortalInstallWorkflow.php',
'PhabricatorDashboardPortalListController' => 'applications/dashboard/controller/portal/PhabricatorDashboardPortalListController.php',
'PhabricatorDashboardPortalMenuItem' => 'applications/dashboard/menuitem/PhabricatorDashboardPortalMenuItem.php',
'PhabricatorDashboardPortalNameTransaction' => 'applications/dashboard/xaction/portal/PhabricatorDashboardPortalNameTransaction.php',
@@ -2968,20 +2973,27 @@
'PhabricatorDashboardPortalViewController' => 'applications/dashboard/controller/portal/PhabricatorDashboardPortalViewController.php',
'PhabricatorDashboardProfileController' => 'applications/dashboard/controller/PhabricatorDashboardProfileController.php',
'PhabricatorDashboardProfileMenuItem' => 'applications/search/menuitem/PhabricatorDashboardProfileMenuItem.php',
+ 'PhabricatorDashboardProjectInstallWorkflow' => 'applications/dashboard/install/PhabricatorDashboardProjectInstallWorkflow.php',
'PhabricatorDashboardQuery' => 'applications/dashboard/query/PhabricatorDashboardQuery.php',
+ 'PhabricatorDashboardQueryPanelApplicationEditField' => 'applications/dashboard/editfield/PhabricatorDashboardQueryPanelApplicationEditField.php',
+ 'PhabricatorDashboardQueryPanelApplicationTransaction' => 'applications/dashboard/xaction/panel/PhabricatorDashboardQueryPanelApplicationTransaction.php',
'PhabricatorDashboardQueryPanelInstallController' => 'applications/dashboard/controller/PhabricatorDashboardQueryPanelInstallController.php',
+ 'PhabricatorDashboardQueryPanelQueryEditField' => 'applications/dashboard/editfield/PhabricatorDashboardQueryPanelQueryEditField.php',
+ 'PhabricatorDashboardQueryPanelQueryTransaction' => 'applications/dashboard/xaction/panel/PhabricatorDashboardQueryPanelQueryTransaction.php',
'PhabricatorDashboardQueryPanelType' => 'applications/dashboard/paneltype/PhabricatorDashboardQueryPanelType.php',
'PhabricatorDashboardRemarkupRule' => 'applications/dashboard/remarkup/PhabricatorDashboardRemarkupRule.php',
'PhabricatorDashboardRemovePanelController' => 'applications/dashboard/controller/PhabricatorDashboardRemovePanelController.php',
'PhabricatorDashboardRenderingEngine' => 'applications/dashboard/engine/PhabricatorDashboardRenderingEngine.php',
'PhabricatorDashboardSchemaSpec' => 'applications/dashboard/storage/PhabricatorDashboardSchemaSpec.php',
'PhabricatorDashboardSearchEngine' => 'applications/dashboard/query/PhabricatorDashboardSearchEngine.php',
+ 'PhabricatorDashboardTabsPanelTabsTransaction' => 'applications/dashboard/xaction/panel/PhabricatorDashboardTabsPanelTabsTransaction.php',
'PhabricatorDashboardTabsPanelType' => 'applications/dashboard/paneltype/PhabricatorDashboardTabsPanelType.php',
+ 'PhabricatorDashboardTextPanelTextTransaction' => 'applications/dashboard/xaction/panel/PhabricatorDashboardTextPanelTextTransaction.php',
'PhabricatorDashboardTextPanelType' => 'applications/dashboard/paneltype/PhabricatorDashboardTextPanelType.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',
+ 'PhabricatorDashboardViewController' => 'applications/dashboard/controller/dashboard/PhabricatorDashboardViewController.php',
'PhabricatorDataCacheSpec' => 'applications/cache/spec/PhabricatorDataCacheSpec.php',
'PhabricatorDataNotAttachedException' => 'infrastructure/storage/lisk/PhabricatorDataNotAttachedException.php',
'PhabricatorDatabaseRef' => 'infrastructure/cluster/PhabricatorDatabaseRef.php',
@@ -4196,6 +4208,7 @@
'PhabricatorProjectTransactionQuery' => 'applications/project/query/PhabricatorProjectTransactionQuery.php',
'PhabricatorProjectTransactionType' => 'applications/project/xaction/PhabricatorProjectTransactionType.php',
'PhabricatorProjectTrigger' => 'applications/project/storage/PhabricatorProjectTrigger.php',
+ 'PhabricatorProjectTriggerAddProjectsRule' => 'applications/project/trigger/PhabricatorProjectTriggerAddProjectsRule.php',
'PhabricatorProjectTriggerController' => 'applications/project/controller/trigger/PhabricatorProjectTriggerController.php',
'PhabricatorProjectTriggerCorruptionException' => 'applications/project/exception/PhabricatorProjectTriggerCorruptionException.php',
'PhabricatorProjectTriggerEditController' => 'applications/project/controller/trigger/PhabricatorProjectTriggerEditController.php',
@@ -6215,6 +6228,7 @@
'DifferentialRevisionIDCommitMessageField' => 'DifferentialCommitMessageField',
'DifferentialRevisionInlineTransaction' => 'PhabricatorModularTransactionType',
'DifferentialRevisionInlinesController' => 'DifferentialController',
+ 'DifferentialRevisionJIRAIssueURIsHeraldField' => 'DifferentialRevisionHeraldField',
'DifferentialRevisionListController' => 'DifferentialController',
'DifferentialRevisionListView' => 'AphrontView',
'DifferentialRevisionMailReceiver' => 'PhabricatorObjectMailReceiver',
@@ -8867,8 +8881,8 @@
),
'PhabricatorDashboardAddPanelController' => 'PhabricatorDashboardController',
'PhabricatorDashboardApplication' => 'PhabricatorApplication',
+ 'PhabricatorDashboardApplicationInstallWorkflow' => 'PhabricatorDashboardInstallWorkflow',
'PhabricatorDashboardArchiveController' => 'PhabricatorDashboardController',
- 'PhabricatorDashboardArrangeController' => 'PhabricatorDashboardProfileController',
'PhabricatorDashboardConsoleController' => 'PhabricatorDashboardController',
'PhabricatorDashboardController' => 'PhabricatorController',
'PhabricatorDashboardDAO' => 'PhabricatorLiskDAO',
@@ -8876,48 +8890,46 @@
'PhabricatorDashboardDashboardPHIDType' => 'PhabricatorPHIDType',
'PhabricatorDashboardDatasource' => 'PhabricatorTypeaheadDatasource',
'PhabricatorDashboardEditController' => 'PhabricatorDashboardController',
+ 'PhabricatorDashboardFavoritesInstallWorkflow' => 'PhabricatorDashboardApplicationInstallWorkflow',
+ 'PhabricatorDashboardHomeInstallWorkflow' => 'PhabricatorDashboardApplicationInstallWorkflow',
'PhabricatorDashboardIconSet' => 'PhabricatorIconSet',
'PhabricatorDashboardInstall' => 'PhabricatorDashboardDAO',
'PhabricatorDashboardInstallController' => 'PhabricatorDashboardController',
+ 'PhabricatorDashboardInstallWorkflow' => 'Phobject',
'PhabricatorDashboardLayoutConfig' => 'Phobject',
'PhabricatorDashboardListController' => 'PhabricatorDashboardController',
- 'PhabricatorDashboardManageController' => 'PhabricatorDashboardProfileController',
'PhabricatorDashboardMovePanelController' => 'PhabricatorDashboardController',
'PhabricatorDashboardNgrams' => 'PhabricatorSearchNgrams',
+ 'PhabricatorDashboardObjectInstallWorkflow' => 'PhabricatorDashboardInstallWorkflow',
'PhabricatorDashboardPanel' => array(
'PhabricatorDashboardDAO',
'PhabricatorApplicationTransactionInterface',
'PhabricatorPolicyInterface',
- 'PhabricatorCustomFieldInterface',
'PhabricatorFlaggableInterface',
'PhabricatorDestructibleInterface',
'PhabricatorNgramsInterface',
),
'PhabricatorDashboardPanelArchiveController' => 'PhabricatorDashboardController',
- 'PhabricatorDashboardPanelCoreCustomField' => array(
- 'PhabricatorDashboardPanelCustomField',
- 'PhabricatorStandardCustomFieldInterface',
- ),
- 'PhabricatorDashboardPanelCustomField' => 'PhabricatorCustomField',
'PhabricatorDashboardPanelDatasource' => 'PhabricatorTypeaheadDatasource',
'PhabricatorDashboardPanelEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod',
'PhabricatorDashboardPanelEditController' => 'PhabricatorDashboardController',
'PhabricatorDashboardPanelEditEngine' => 'PhabricatorEditEngine',
- 'PhabricatorDashboardPanelEditproController' => 'PhabricatorDashboardController',
'PhabricatorDashboardPanelHasDashboardEdgeType' => 'PhabricatorEdgeType',
'PhabricatorDashboardPanelListController' => 'PhabricatorDashboardController',
+ 'PhabricatorDashboardPanelNameTransaction' => 'PhabricatorDashboardPanelTransactionType',
'PhabricatorDashboardPanelNgrams' => 'PhabricatorSearchNgrams',
'PhabricatorDashboardPanelPHIDType' => 'PhabricatorPHIDType',
+ 'PhabricatorDashboardPanelPropertyTransaction' => 'PhabricatorDashboardPanelTransactionType',
'PhabricatorDashboardPanelQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorDashboardPanelRenderController' => 'PhabricatorDashboardController',
'PhabricatorDashboardPanelRenderingEngine' => 'Phobject',
- 'PhabricatorDashboardPanelSearchApplicationCustomField' => 'PhabricatorStandardCustomField',
'PhabricatorDashboardPanelSearchEngine' => 'PhabricatorApplicationSearchEngine',
- 'PhabricatorDashboardPanelSearchQueryCustomField' => 'PhabricatorStandardCustomField',
- 'PhabricatorDashboardPanelTabsCustomField' => 'PhabricatorStandardCustomField',
- 'PhabricatorDashboardPanelTransaction' => 'PhabricatorApplicationTransaction',
+ 'PhabricatorDashboardPanelStatusTransaction' => 'PhabricatorDashboardPanelTransactionType',
+ 'PhabricatorDashboardPanelTabsController' => 'PhabricatorDashboardController',
+ 'PhabricatorDashboardPanelTransaction' => 'PhabricatorModularTransaction',
'PhabricatorDashboardPanelTransactionEditor' => 'PhabricatorApplicationTransactionEditor',
'PhabricatorDashboardPanelTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
+ 'PhabricatorDashboardPanelTransactionType' => 'PhabricatorModularTransactionType',
'PhabricatorDashboardPanelType' => 'Phobject',
'PhabricatorDashboardPanelViewController' => 'PhabricatorDashboardController',
'PhabricatorDashboardPortal' => array(
@@ -8927,10 +8939,12 @@
'PhabricatorDestructibleInterface',
),
'PhabricatorDashboardPortalController' => 'PhabricatorDashboardController',
+ 'PhabricatorDashboardPortalDatasource' => 'PhabricatorTypeaheadDatasource',
'PhabricatorDashboardPortalEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod',
'PhabricatorDashboardPortalEditController' => 'PhabricatorDashboardPortalController',
'PhabricatorDashboardPortalEditEngine' => 'PhabricatorEditEngine',
'PhabricatorDashboardPortalEditor' => 'PhabricatorApplicationTransactionEditor',
+ 'PhabricatorDashboardPortalInstallWorkflow' => 'PhabricatorDashboardObjectInstallWorkflow',
'PhabricatorDashboardPortalListController' => 'PhabricatorDashboardPortalController',
'PhabricatorDashboardPortalMenuItem' => 'PhabricatorProfileMenuItem',
'PhabricatorDashboardPortalNameTransaction' => 'PhabricatorDashboardPortalTransactionType',
@@ -8946,15 +8960,22 @@
'PhabricatorDashboardPortalViewController' => 'PhabricatorDashboardPortalController',
'PhabricatorDashboardProfileController' => 'PhabricatorController',
'PhabricatorDashboardProfileMenuItem' => 'PhabricatorProfileMenuItem',
+ 'PhabricatorDashboardProjectInstallWorkflow' => 'PhabricatorDashboardObjectInstallWorkflow',
'PhabricatorDashboardQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
+ 'PhabricatorDashboardQueryPanelApplicationEditField' => 'PhabricatorEditField',
+ 'PhabricatorDashboardQueryPanelApplicationTransaction' => 'PhabricatorDashboardPanelPropertyTransaction',
'PhabricatorDashboardQueryPanelInstallController' => 'PhabricatorDashboardController',
+ 'PhabricatorDashboardQueryPanelQueryEditField' => 'PhabricatorEditField',
+ 'PhabricatorDashboardQueryPanelQueryTransaction' => 'PhabricatorDashboardPanelPropertyTransaction',
'PhabricatorDashboardQueryPanelType' => 'PhabricatorDashboardPanelType',
'PhabricatorDashboardRemarkupRule' => 'PhabricatorObjectRemarkupRule',
'PhabricatorDashboardRemovePanelController' => 'PhabricatorDashboardController',
'PhabricatorDashboardRenderingEngine' => 'Phobject',
'PhabricatorDashboardSchemaSpec' => 'PhabricatorConfigSchemaSpec',
'PhabricatorDashboardSearchEngine' => 'PhabricatorApplicationSearchEngine',
+ 'PhabricatorDashboardTabsPanelTabsTransaction' => 'PhabricatorDashboardPanelPropertyTransaction',
'PhabricatorDashboardTabsPanelType' => 'PhabricatorDashboardPanelType',
+ 'PhabricatorDashboardTextPanelTextTransaction' => 'PhabricatorDashboardPanelPropertyTransaction',
'PhabricatorDashboardTextPanelType' => 'PhabricatorDashboardPanelType',
'PhabricatorDashboardTransaction' => 'PhabricatorApplicationTransaction',
'PhabricatorDashboardTransactionEditor' => 'PhabricatorApplicationTransactionEditor',
@@ -10363,6 +10384,7 @@
'PhabricatorIndexableInterface',
'PhabricatorDestructibleInterface',
),
+ 'PhabricatorProjectTriggerAddProjectsRule' => 'PhabricatorProjectTriggerRule',
'PhabricatorProjectTriggerController' => 'PhabricatorProjectController',
'PhabricatorProjectTriggerCorruptionException' => 'Exception',
'PhabricatorProjectTriggerEditController' => 'PhabricatorProjectTriggerController',
diff --git a/src/applications/dashboard/application/PhabricatorDashboardApplication.php b/src/applications/dashboard/application/PhabricatorDashboardApplication.php
--- a/src/applications/dashboard/application/PhabricatorDashboardApplication.php
+++ b/src/applications/dashboard/application/PhabricatorDashboardApplication.php
@@ -41,11 +41,12 @@
=> 'PhabricatorDashboardListController',
'view/(?P<id>\d+)/' => 'PhabricatorDashboardViewController',
'archive/(?P<id>\d+)/' => 'PhabricatorDashboardArchiveController',
- 'manage/(?P<id>\d+)/' => 'PhabricatorDashboardManageController',
- 'arrange/(?P<id>\d+)/' => 'PhabricatorDashboardArrangeController',
'create/' => 'PhabricatorDashboardEditController',
'edit/(?:(?P<id>\d+)/)?' => 'PhabricatorDashboardEditController',
- 'install/(?:(?P<id>\d+)/)?' => 'PhabricatorDashboardInstallController',
+ 'install/(?P<id>\d+)/'.
+ '(?:(?P<workflowKey>[^/]+)/'.
+ '(?:(?P<modeKey>[^/]+)/)?)?' =>
+ 'PhabricatorDashboardInstallController',
'console/' => 'PhabricatorDashboardConsoleController',
'addpanel/(?P<id>\d+)/' => 'PhabricatorDashboardAddPanelController',
'movepanel/(?P<id>\d+)/' => 'PhabricatorDashboardMovePanelController',
@@ -56,13 +57,13 @@
'PhabricatorDashboardQueryPanelInstallController',
'(?:query/(?P<queryKey>[^/]+)/)?'
=> 'PhabricatorDashboardPanelListController',
- 'create/' => 'PhabricatorDashboardPanelEditController',
- $this->getEditRoutePattern('editpro/')
- => 'PhabricatorDashboardPanelEditproController',
- 'edit/(?:(?P<id>\d+)/)?' => 'PhabricatorDashboardPanelEditController',
+ $this->getEditRoutePattern('edit/')
+ => 'PhabricatorDashboardPanelEditController',
'render/(?P<id>\d+)/' => 'PhabricatorDashboardPanelRenderController',
'archive/(?P<id>\d+)/'
=> 'PhabricatorDashboardPanelArchiveController',
+ 'tabs/(?P<id>\d+)/(?P<op>add|move|remove|rename)/'
+ => 'PhabricatorDashboardPanelTabsController',
),
),
'/portal/' => array(
diff --git a/src/applications/dashboard/controller/PhabricatorDashboardArrangeController.php b/src/applications/dashboard/controller/PhabricatorDashboardArrangeController.php
deleted file mode 100644
--- a/src/applications/dashboard/controller/PhabricatorDashboardArrangeController.php
+++ /dev/null
@@ -1,79 +0,0 @@
-<?php
-
-final class PhabricatorDashboardArrangeController
- extends PhabricatorDashboardProfileController {
-
- public function shouldAllowPublic() {
- return true;
- }
-
- public function handleRequest(AphrontRequest $request) {
- $viewer = $request->getViewer();
- $id = $request->getURIData('id');
-
- $dashboard = id(new PhabricatorDashboardQuery())
- ->setViewer($viewer)
- ->withIDs(array($id))
- ->needPanels(true)
- ->executeOne();
- if (!$dashboard) {
- return new Aphront404Response();
- }
- $this->setDashboard($dashboard);
-
- $can_edit = PhabricatorPolicyFilter::hasCapability(
- $viewer,
- $dashboard,
- PhabricatorPolicyCapability::CAN_EDIT);
-
- $title = $dashboard->getName();
- $crumbs = $this->buildApplicationCrumbs();
- $crumbs->addTextCrumb(pht('Arrange'));
- $header = $this->buildHeaderView();
-
- $info_view = null;
- if (!$can_edit) {
- $no_edit = pht(
- 'You do not have permission to edit this dashboard.');
-
- $info_view = id(new PHUIInfoView())
- ->setSeverity(PHUIInfoView::SEVERITY_NOTICE)
- ->setErrors(array($no_edit));
- }
-
- $rendered_dashboard = id(new PhabricatorDashboardRenderingEngine())
- ->setViewer($viewer)
- ->setDashboard($dashboard)
- ->setArrangeMode($can_edit)
- ->renderDashboard();
-
- $dashboard_box = id(new PHUIBoxView())
- ->addClass('dashboard-preview-box')
- ->appendChild($rendered_dashboard);
-
- $install_button = id(new PHUIButtonView())
- ->setTag('a')
- ->setText('Install Dashboard')
- ->setIcon('fa-plus')
- ->setWorkflow(true)
- ->setHref($this->getApplicationURI("/install/{$id}/"));
- $header->addActionLink($install_button);
-
- $view = id(new PHUITwoColumnView())
- ->setHeader($header)
- ->setFooter(array(
- $info_view,
- $dashboard_box,
- ));
-
- $navigation = $this->buildSideNavView('arrange');
-
- return $this->newPage()
- ->setTitle($title)
- ->setCrumbs($crumbs)
- ->setNavigation($navigation)
- ->appendChild($view);
-
- }
-
-}
diff --git a/src/applications/dashboard/controller/PhabricatorDashboardInstallController.php b/src/applications/dashboard/controller/PhabricatorDashboardInstallController.php
deleted file mode 100644
--- a/src/applications/dashboard/controller/PhabricatorDashboardInstallController.php
+++ /dev/null
@@ -1,141 +0,0 @@
-<?php
-
-final class PhabricatorDashboardInstallController
- extends PhabricatorDashboardController {
-
- public function handleRequest(AphrontRequest $request) {
- $viewer = $request->getViewer();
- $id = $request->getURIData('id');
-
- $dashboard = id(new PhabricatorDashboardQuery())
- ->setViewer($viewer)
- ->withIDs(array($id))
- ->executeOne();
- if (!$dashboard) {
- return new Aphront404Response();
- }
-
- $cancel_uri = $this->getApplicationURI(
- 'view/'.$dashboard->getID().'/');
-
- $home_app = new PhabricatorHomeApplication();
-
- $options = array();
- $options['home'] = array(
- 'personal' =>
- array(
- 'capability' => PhabricatorPolicyCapability::CAN_VIEW,
- 'application' => $home_app,
- 'name' => pht('Personal Dashboard'),
- 'value' => 'personal',
- 'description' => pht('Places this dashboard as a menu item on home '.
- 'as a personal menu item. It will only be on your personal '.
- 'home.'),
- ),
- 'global' =>
- array(
- 'capability' => PhabricatorPolicyCapability::CAN_EDIT,
- 'application' => $home_app,
- 'name' => pht('Global Dashboard'),
- 'value' => 'global',
- 'description' => pht('Places this dashboard as a menu item on home '.
- 'as a global menu item. It will be available to all users.'),
- ),
- );
-
-
- $errors = array();
- $v_name = null;
- if ($request->isFormPost()) {
- $menuitem = new PhabricatorDashboardProfileMenuItem();
- $dashboard_phid = $dashboard->getPHID();
- $home = new PhabricatorHomeApplication();
- $v_name = $request->getStr('name');
- $v_home = $request->getStr('home');
-
- if ($v_home) {
- $application = $options['home'][$v_home]['application'];
- $capability = $options['home'][$v_home]['capability'];
-
- $can_edit_home = PhabricatorPolicyFilter::hasCapability(
- $viewer,
- $application,
- $capability);
-
- if (!$can_edit_home) {
- $errors[] = pht(
- 'You do not have permission to install a dashboard on home.');
- }
- } else {
- $errors[] = pht(
- 'You must select a destination to install this dashboard.');
- }
-
- $v_phid = $viewer->getPHID();
- if ($v_home == 'global') {
- $v_phid = null;
- }
-
- if (!$errors) {
- $install = PhabricatorProfileMenuItemConfiguration::initializeNewItem(
- $home,
- $menuitem,
- $v_phid);
-
- $install->setMenuItemProperty('dashboardPHID', $dashboard_phid);
- $install->setMenuItemProperty('name', $v_name);
- $install->setMenuItemOrder(1);
-
- $xactions = array();
-
- $editor = id(new PhabricatorProfileMenuEditor())
- ->setActor($viewer)
- ->setContinueOnNoEffect(true)
- ->setContinueOnMissingFields(true)
- ->setContentSourceFromRequest($request);
-
- $editor->applyTransactions($install, $xactions);
-
- $view_uri = '/home/menu/view/'.$install->getID().'/';
-
- return id(new AphrontRedirectResponse())->setURI($view_uri);
- }
- }
-
- $form = id(new AphrontFormView())
- ->setUser($viewer)
- ->appendChild(
- id(new AphrontFormTextControl())
- ->setLabel(pht('Menu Label'))
- ->setName('name')
- ->setValue($v_name));
-
- $radio = id(new AphrontFormRadioButtonControl())
- ->setLabel(pht('Home Menu'))
- ->setName('home');
-
- foreach ($options['home'] as $type => $option) {
- $can_edit = PhabricatorPolicyFilter::hasCapability(
- $viewer,
- $option['application'],
- $option['capability']);
- if ($can_edit) {
- $radio->addButton(
- $option['value'],
- $option['name'],
- $option['description']);
- }
- }
-
- $form->appendChild($radio);
-
- return $this->newDialog()
- ->setTitle(pht('Install Dashboard'))
- ->setErrors($errors)
- ->setWidth(AphrontDialogView::WIDTH_FORM)
- ->appendChild($form->buildLayoutView())
- ->addCancelButton($cancel_uri)
- ->addSubmitButton(pht('Install Dashboard'));
- }
-
-}
diff --git a/src/applications/dashboard/controller/PhabricatorDashboardPanelEditController.php b/src/applications/dashboard/controller/PhabricatorDashboardPanelEditController.php
deleted file mode 100644
--- a/src/applications/dashboard/controller/PhabricatorDashboardPanelEditController.php
+++ /dev/null
@@ -1,354 +0,0 @@
-<?php
-
-final class PhabricatorDashboardPanelEditController
- extends PhabricatorDashboardController {
-
- public function handleRequest(AphrontRequest $request) {
- $viewer = $request->getViewer();
- $id = $request->getURIData('id');
-
- // If the user is trying to create a panel directly on a dashboard, make
- // sure they have permission to see and edit the dashboard.
-
- $dashboard_id = $request->getInt('dashboardID');
- $dashboard = null;
- if ($dashboard_id) {
- $dashboard = id(new PhabricatorDashboardQuery())
- ->setViewer($viewer)
- ->withIDs(array($dashboard_id))
- ->requireCapabilities(
- array(
- PhabricatorPolicyCapability::CAN_VIEW,
- PhabricatorPolicyCapability::CAN_EDIT,
- ))
- ->executeOne();
- if (!$dashboard) {
- return new Aphront404Response();
- }
-
- $manage_uri = $this->getApplicationURI('arrange/'.$dashboard_id.'/');
- }
-
- if ($id) {
- $is_create = false;
-
- if ($dashboard) {
- $capabilities = array(
- PhabricatorPolicyCapability::CAN_VIEW,
- );
- } else {
- $capabilities = array(
- PhabricatorPolicyCapability::CAN_VIEW,
- PhabricatorPolicyCapability::CAN_EDIT,
- );
- }
-
- $panel = id(new PhabricatorDashboardPanelQuery())
- ->setViewer($viewer)
- ->withIDs(array($id))
- ->requireCapabilities($capabilities)
- ->executeOne();
- if (!$panel) {
- return new Aphront404Response();
- }
-
- } else {
- $is_create = true;
-
- $panel = PhabricatorDashboardPanel::initializeNewPanel($viewer);
- $types = PhabricatorDashboardPanelType::getAllPanelTypes();
- $type = $request->getStr('type');
- if (empty($types[$type])) {
- return $this->processPanelTypeRequest($request);
- }
-
- $panel->setPanelType($type);
- }
-
- if ($is_create) {
- $title = pht('Create New Panel');
- $button = pht('Create Panel');
- $header_icon = 'fa-plus-square';
- if ($dashboard) {
- $cancel_uri = $manage_uri;
- } else {
- $cancel_uri = $this->getApplicationURI('panel/');
- }
- } else {
- $title = pht('Edit Panel: %s', $panel->getName());
- $button = pht('Save Panel');
- $header_icon = 'fa-pencil';
- if ($dashboard) {
- $cancel_uri = $manage_uri;
- } else {
- $cancel_uri = '/'.$panel->getMonogram();
- }
- }
-
- $v_name = $panel->getName();
- $e_name = true;
-
- $field_list = PhabricatorCustomField::getObjectFields(
- $panel,
- PhabricatorCustomField::ROLE_EDIT);
- $field_list
- ->setViewer($viewer)
- ->readFieldsFromStorage($panel);
-
- if ($is_create && !$request->isFormPost()) {
- $panel->requireImplementation()->initializeFieldsFromRequest(
- $panel,
- $field_list,
- $request);
- }
-
- $validation_exception = null;
-
- // NOTE: We require 'edit' to distinguish between the "Choose a Type"
- // and "Create a Panel" dialogs.
-
- if ($request->isFormPost() && $request->getBool('edit')) {
- $v_name = $request->getStr('name');
- $v_view_policy = $request->getStr('viewPolicy');
- $v_edit_policy = $request->getStr('editPolicy');
-
- $type_name = PhabricatorDashboardPanelTransaction::TYPE_NAME;
- $type_view_policy = PhabricatorTransactions::TYPE_VIEW_POLICY;
- $type_edit_policy = PhabricatorTransactions::TYPE_EDIT_POLICY;
-
- $xactions = array();
-
- $xactions[] = id(new PhabricatorDashboardPanelTransaction())
- ->setTransactionType($type_name)
- ->setNewValue($v_name);
-
- $xactions[] = id(new PhabricatorDashboardPanelTransaction())
- ->setTransactionType($type_view_policy)
- ->setNewValue($v_view_policy);
-
- $xactions[] = id(new PhabricatorDashboardPanelTransaction())
- ->setTransactionType($type_edit_policy)
- ->setNewValue($v_edit_policy);
-
- $field_xactions = $field_list->buildFieldTransactionsFromRequest(
- new PhabricatorDashboardPanelTransaction(),
- $request);
- $xactions = array_merge($xactions, $field_xactions);
-
- try {
- $editor = id(new PhabricatorDashboardPanelTransactionEditor())
- ->setActor($viewer)
- ->setContinueOnNoEffect(true)
- ->setContentSourceFromRequest($request)
- ->applyTransactions($panel, $xactions);
-
- // If we're creating a panel directly on a dashboard, add it now.
- if ($dashboard && $is_create) {
- PhabricatorDashboardTransactionEditor::addPanelToDashboard(
- $viewer,
- PhabricatorContentSource::newFromRequest($request),
- $panel,
- $dashboard,
- $request->getInt('column', 0));
- }
-
- if ($dashboard) {
- $done_uri = $manage_uri;
- } else {
- $done_uri = '/'.$panel->getMonogram();
- }
-
- return id(new AphrontRedirectResponse())->setURI($done_uri);
- } catch (PhabricatorApplicationTransactionValidationException $ex) {
- $validation_exception = $ex;
-
- $e_name = $validation_exception->getShortMessage($type_name);
-
- $panel->setViewPolicy($v_view_policy);
- $panel->setEditPolicy($v_edit_policy);
- }
- }
-
- // NOTE: We're setting the submit URI explicitly because we need to edit
- // a different panel if we just cloned the original panel.
- if ($is_create) {
- $submit_uri = $this->getApplicationURI('panel/edit/');
- } else {
- $submit_uri = $this->getApplicationURI('panel/edit/'.$panel->getID().'/');
- }
-
- $policies = id(new PhabricatorPolicyQuery())
- ->setViewer($viewer)
- ->setObject($panel)
- ->execute();
-
- $form = id(new AphrontFormView())
- ->setUser($viewer)
- ->setAction($submit_uri)
- ->addHiddenInput('edit', true)
- ->addHiddenInput('dashboardID', $request->getInt('dashboardID'))
- ->addHiddenInput('column', $request->getInt('column'))
- ->appendChild(
- id(new AphrontFormTextControl())
- ->setLabel(pht('Name'))
- ->setName('name')
- ->setValue($v_name)
- ->setError($e_name));
-
- if (!$request->isAjax() || !$is_create) {
- $form
- ->appendChild(
- id(new AphrontFormPolicyControl())
- ->setName('viewPolicy')
- ->setPolicyObject($panel)
- ->setCapability(PhabricatorPolicyCapability::CAN_VIEW)
- ->setPolicies($policies))
- ->appendChild(
- id(new AphrontFormPolicyControl())
- ->setName('editPolicy')
- ->setPolicyObject($panel)
- ->setCapability(PhabricatorPolicyCapability::CAN_EDIT)
- ->setPolicies($policies));
- }
-
- $field_list->appendFieldsToForm($form);
-
- $crumbs = $this->buildApplicationCrumbs();
- $crumbs->addTextCrumb(
- pht('Panels'),
- $this->getApplicationURI('panel/'));
- if ($is_create) {
- $crumbs->addTextCrumb(pht('New Panel'));
- $form->addHiddenInput('type', $panel->getPanelType());
- } else {
- $crumbs->addTextCrumb(
- $panel->getMonogram(),
- '/'.$panel->getMonogram());
- $crumbs->addTextCrumb(pht('Edit'));
- }
- $crumbs->setBorder(true);
-
- if ($request->isAjax()) {
- return $this->newDialog()
- ->setTitle($title)
- ->setSubmitURI($submit_uri)
- ->setWidth(AphrontDialogView::WIDTH_FORM)
- ->setValidationException($validation_exception)
- ->appendChild($form->buildLayoutView())
- ->addCancelButton($cancel_uri)
- ->addSubmitButton($button);
- } else {
- $form
- ->appendChild(
- id(new AphrontFormSubmitControl())
- ->setValue($button)
- ->addCancelButton($cancel_uri));
- }
-
- $box = id(new PHUIObjectBoxView())
- ->setHeaderText(pht('Panel'))
- ->setValidationException($validation_exception)
- ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
- ->setForm($form);
-
- $header = id(new PHUIHeaderView())
- ->setHeader($title)
- ->setHeaderIcon($header_icon);
-
- $view = id(new PHUITwoColumnView())
- ->setHeader($header)
- ->setFooter($box);
-
- return $this->newPage()
- ->setTitle($title)
- ->setCrumbs($crumbs)
- ->appendChild($view);
- }
-
- private function processPanelTypeRequest(AphrontRequest $request) {
- $viewer = $request->getUser();
-
- $types = PhabricatorDashboardPanelType::getAllPanelTypes();
-
- $v_type = null;
- $errors = array();
- if ($request->isFormPost()) {
- $v_type = $request->getStr('type');
- if (!isset($types[$v_type])) {
- $errors[] = pht('You must select a type of panel to create.');
- }
- }
-
- $cancel_uri = $this->getApplicationURI('panel/');
-
- if (!$v_type) {
- $v_type = key($types);
- }
-
- $panel_types = id(new AphrontFormRadioButtonControl())
- ->setName('type')
- ->setValue($v_type);
-
- foreach ($types as $key => $type) {
- $panel_types->addButton(
- $key,
- $type->getPanelTypeName(),
- $type->getPanelTypeDescription());
- }
-
- $form = id(new AphrontFormView())
- ->setUser($viewer)
- ->addHiddenInput('dashboardID', $request->getInt('dashboardID'))
- ->addHiddenInput('column', $request->getInt('column'))
- ->appendRemarkupInstructions(
- pht(
- 'Choose the type of dashboard panel to create:'))
- ->appendChild($panel_types);
-
- if ($request->isAjax()) {
- return $this->newDialog()
- ->setTitle(pht('Add New Panel'))
- ->setWidth(AphrontDialogView::WIDTH_FORM)
- ->setErrors($errors)
- ->appendChild($form->buildLayoutView())
- ->addCancelbutton($cancel_uri)
- ->addSubmitButton(pht('Continue'));
- } else {
- $form->appendChild(
- id(new AphrontFormSubmitControl())
- ->setValue(pht('Continue'))
- ->addCancelButton($cancel_uri));
- }
-
- $title = pht('Create Dashboard Panel');
- $header_icon = 'fa-plus-square';
-
- $crumbs = $this->buildApplicationCrumbs();
- $crumbs->addTextCrumb(
- pht('Panels'),
- $this->getApplicationURI('panel/'));
- $crumbs->addTextCrumb(pht('New Panel'));
- $crumbs->setBorder(true);
-
- $box = id(new PHUIObjectBoxView())
- ->setHeaderText(pht('Panel'))
- ->setFormErrors($errors)
- ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
- ->setForm($form);
-
- $header = id(new PHUIHeaderView())
- ->setHeader($title)
- ->setHeaderIcon($header_icon);
-
- $view = id(new PHUITwoColumnView())
- ->setHeader($header)
- ->setFooter($box);
-
- return $this->newPage()
- ->setTitle($title)
- ->setCrumbs($crumbs)
- ->appendChild($view);
- }
-
-
-}
diff --git a/src/applications/dashboard/controller/PhabricatorDashboardPanelEditproController.php b/src/applications/dashboard/controller/PhabricatorDashboardPanelEditproController.php
deleted file mode 100644
--- a/src/applications/dashboard/controller/PhabricatorDashboardPanelEditproController.php
+++ /dev/null
@@ -1,105 +0,0 @@
-<?php
-
-final class PhabricatorDashboardPanelEditproController
- extends PhabricatorDashboardController {
-
- public function handleRequest(AphrontRequest $request) {
- $engine = id(new PhabricatorDashboardPanelEditEngine())
- ->setController($this);
-
- $id = $request->getURIData('id');
- if (!$id) {
- $list_uri = $this->getApplicationURI('panel/');
-
- $panel_type = $request->getStr('panelType');
- $panel_types = PhabricatorDashboardPanelType::getAllPanelTypes();
- if (empty($panel_types[$panel_type])) {
- return $this->buildPanelTypeResponse($list_uri);
- }
-
- $engine
- ->addContextParameter('panelType', $panel_type)
- ->setPanelType($panel_type);
- }
-
- return $engine->buildResponse();
- }
-
- private function buildPanelTypeResponse($cancel_uri) {
- $panel_types = PhabricatorDashboardPanelType::getAllPanelTypes();
-
- $viewer = $this->getViewer();
- $request = $this->getRequest();
-
- $e_type = null;
- $errors = array();
- if ($request->isFormPost()) {
- $e_type = pht('Required');
- $errors[] = pht(
- 'To create a new dashboard panel, you must select a panel type.');
- }
-
- $type_control = id(new AphrontFormRadioButtonControl())
- ->setLabel(pht('Panel Type'))
- ->setName('panelType')
- ->setError($e_type);
-
- foreach ($panel_types as $key => $type) {
- $type_control->addButton(
- $key,
- $type->getPanelTypeName(),
- $type->getPanelTypeDescription());
- }
-
- $form = id(new AphrontFormView())
- ->setUser($viewer)
- ->appendRemarkupInstructions(
- pht('Choose the type of dashboard panel to create:'))
- ->appendChild($type_control);
-
- if ($request->isAjax()) {
- return $this->newDialog()
- ->setTitle(pht('Add New Panel'))
- ->setWidth(AphrontDialogView::WIDTH_FORM)
- ->setErrors($errors)
- ->appendForm($form)
- ->addCancelButton($cancel_uri)
- ->addSubmitButton(pht('Continue'));
- }
-
- $form->appendChild(
- id(new AphrontFormSubmitControl())
- ->setValue(pht('Continue'))
- ->addCancelButton($cancel_uri));
-
- $title = pht('Create Dashboard Panel');
- $header_icon = 'fa-plus-square';
-
- $crumbs = $this->buildApplicationCrumbs();
- $crumbs->addTextCrumb(
- pht('Panels'),
- $this->getApplicationURI('panel/'));
- $crumbs->addTextCrumb(pht('New Panel'));
- $crumbs->setBorder(true);
-
- $box = id(new PHUIObjectBoxView())
- ->setHeaderText(pht('Panel'))
- ->setFormErrors($errors)
- ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
- ->setForm($form);
-
- $header = id(new PHUIHeaderView())
- ->setHeader($title)
- ->setHeaderIcon($header_icon);
-
- $view = id(new PHUITwoColumnView())
- ->setHeader($header)
- ->setFooter($box);
-
- return $this->newPage()
- ->setTitle($title)
- ->setCrumbs($crumbs)
- ->appendChild($view);
- }
-
-}
diff --git a/src/applications/dashboard/controller/PhabricatorDashboardProfileController.php b/src/applications/dashboard/controller/PhabricatorDashboardProfileController.php
--- a/src/applications/dashboard/controller/PhabricatorDashboardProfileController.php
+++ b/src/applications/dashboard/controller/PhabricatorDashboardProfileController.php
@@ -14,10 +14,6 @@
return $this->dashboard;
}
- public function buildApplicationMenu() {
- return $this->buildSideNavView()->getMenu();
- }
-
protected function buildHeaderView() {
$viewer = $this->getViewer();
$dashboard = $this->getDashboard();
@@ -49,50 +45,10 @@
$dashboard = $this->getDashboard();
if ($dashboard) {
- $id = $dashboard->getID();
- $dashboard_uri = $this->getApplicationURI("/view/{$id}/");
- $crumbs->addTextCrumb($dashboard->getName(), $dashboard_uri);
+ $crumbs->addTextCrumb($dashboard->getName(), $dashboard->getURI());
}
return $crumbs;
}
- protected function buildSideNavView($filter = null) {
- $viewer = $this->getViewer();
- $dashboard = $this->getDashboard();
- $id = $dashboard->getID();
-
- $can_edit = PhabricatorPolicyFilter::hasCapability(
- $viewer,
- $dashboard,
- PhabricatorPolicyCapability::CAN_EDIT);
-
- $nav = id(new AphrontSideNavFilterView())
- ->setBaseURI(new PhutilURI($this->getApplicationURI()));
-
- $nav->addLabel(pht('Dashboard'));
-
- $nav->addFilter(
- 'view',
- pht('View Dashboard'),
- $this->getApplicationURI("/view/{$id}/"),
- 'fa-dashboard');
-
- $nav->addFilter(
- 'arrange',
- pht('Arrange Panels'),
- $this->getApplicationURI("/arrange/{$id}/"),
- 'fa-columns');
-
- $nav->addFilter(
- 'manage',
- pht('Manage Dashboard'),
- $this->getApplicationURI("/manage/{$id}/"),
- 'fa-gears');
-
- $nav->selectFilter($filter);
-
- return $nav;
- }
-
}
diff --git a/src/applications/dashboard/controller/PhabricatorDashboardQueryPanelInstallController.php b/src/applications/dashboard/controller/PhabricatorDashboardQueryPanelInstallController.php
--- a/src/applications/dashboard/controller/PhabricatorDashboardQueryPanelInstallController.php
+++ b/src/applications/dashboard/controller/PhabricatorDashboardQueryPanelInstallController.php
@@ -75,7 +75,7 @@
}
if (!$errors) {
- $redirect_uri = "/dashboard/arrange/{$v_dashboard}/";
+ $redirect_uri = "/dashboard/view/{$v_dashboard}/";
$panel_type = id(new PhabricatorDashboardQueryPanelType())
->getPanelTypeKey();
@@ -98,7 +98,8 @@
$xactions = array();
$xactions[] = id(new PhabricatorDashboardPanelTransaction())
- ->setTransactionType(PhabricatorDashboardPanelTransaction::TYPE_NAME)
+ ->setTransactionType(
+ PhabricatorDashboardPanelNameTransaction::TRANSACTIONTYPE)
->setNewValue($v_name);
$xactions[] = id(new PhabricatorDashboardPanelTransaction())
diff --git a/src/applications/dashboard/controller/PhabricatorDashboardRemovePanelController.php b/src/applications/dashboard/controller/PhabricatorDashboardRemovePanelController.php
--- a/src/applications/dashboard/controller/PhabricatorDashboardRemovePanelController.php
+++ b/src/applications/dashboard/controller/PhabricatorDashboardRemovePanelController.php
@@ -42,8 +42,7 @@
return new Aphront404Response();
}
- $redirect_uri = $this->getApplicationURI(
- 'arrange/'.$dashboard->getID().'/');
+ $redirect_uri = $dashboard->getURI();
$layout_config = $dashboard->getLayoutConfigObject();
if ($request->isFormPost()) {
diff --git a/src/applications/dashboard/controller/PhabricatorDashboardViewController.php b/src/applications/dashboard/controller/PhabricatorDashboardViewController.php
deleted file mode 100644
--- a/src/applications/dashboard/controller/PhabricatorDashboardViewController.php
+++ /dev/null
@@ -1,68 +0,0 @@
-<?php
-
-final class PhabricatorDashboardViewController
- extends PhabricatorDashboardProfileController {
-
- public function shouldAllowPublic() {
- return true;
- }
-
- public function handleRequest(AphrontRequest $request) {
- $viewer = $request->getViewer();
- $id = $request->getURIData('id');
-
- $dashboard = id(new PhabricatorDashboardQuery())
- ->setViewer($viewer)
- ->withIDs(array($id))
- ->needPanels(true)
- ->executeOne();
- if (!$dashboard) {
- return new Aphront404Response();
- }
- $this->setDashboard($dashboard);
-
- $dashboard_uri = $this->getApplicationURI("view/{$id}/");
- $title = $dashboard->getName();
- $crumbs = $this->buildApplicationCrumbs();
- $crumbs->addTextCrumb(pht('View'));
-
- if ($dashboard->getPanelPHIDs()) {
- $rendered_dashboard = id(new PhabricatorDashboardRenderingEngine())
- ->setViewer($viewer)
- ->setDashboard($dashboard)
- ->renderDashboard();
- $content = id(new PHUIBoxView())
- ->addClass('dashboard-preview-box')
- ->appendChild($rendered_dashboard);
- } else {
- $content = id(new PHUIInfoView())
- ->setSeverity(PHUIInfoView::SEVERITY_NOTICE)
- ->appendChild(pht('This dashboard has no panels yet.'));
- }
-
- $navigation = $this->buildSideNavView('view');
- $header = $this->buildHeaderView();
-
- $install_button = id(new PHUIButtonView())
- ->setTag('a')
- ->setText('Install Dashboard')
- ->setIcon('fa-plus')
- ->setColor(PHUIButtonView::GREEN)
- ->setWorkflow(true)
- ->setHref($this->getApplicationURI("/install/{$id}/"));
- $header->addActionLink($install_button);
-
- $view = id(new PHUITwoColumnView())
- ->setHeader($header)
- ->setFooter(array(
- $content,
- ));
-
- return $this->newPage()
- ->setTitle($title)
- ->setCrumbs($crumbs)
- ->setNavigation($navigation)
- ->appendChild($view);
- }
-
-}
diff --git a/src/applications/dashboard/controller/PhabricatorDashboardArchiveController.php b/src/applications/dashboard/controller/dashboard/PhabricatorDashboardArchiveController.php
rename from src/applications/dashboard/controller/PhabricatorDashboardArchiveController.php
rename to src/applications/dashboard/controller/dashboard/PhabricatorDashboardArchiveController.php
--- a/src/applications/dashboard/controller/PhabricatorDashboardArchiveController.php
+++ b/src/applications/dashboard/controller/dashboard/PhabricatorDashboardArchiveController.php
@@ -20,7 +20,7 @@
return new Aphront404Response();
}
- $view_uri = $this->getApplicationURI('manage/'.$dashboard->getID().'/');
+ $view_uri = $dashboard->getURI();
if ($request->isFormPost()) {
if ($dashboard->isArchived()) {
diff --git a/src/applications/dashboard/controller/PhabricatorDashboardEditController.php b/src/applications/dashboard/controller/dashboard/PhabricatorDashboardEditController.php
rename from src/applications/dashboard/controller/PhabricatorDashboardEditController.php
rename to src/applications/dashboard/controller/dashboard/PhabricatorDashboardEditController.php
--- a/src/applications/dashboard/controller/PhabricatorDashboardEditController.php
+++ b/src/applications/dashboard/controller/dashboard/PhabricatorDashboardEditController.php
@@ -27,19 +27,6 @@
$v_projects = array_reverse($v_projects);
$is_new = false;
} else {
- if (!$request->getStr('edit')) {
- if ($request->isFormPost()) {
- switch ($request->getStr('template')) {
- case 'empty':
- break;
- default:
- return $this->processBuildTemplateRequest($request);
- }
- } else {
- return $this->processTemplateRequest($request);
- }
- }
-
$dashboard = PhabricatorDashboard::initializeNewDashboard($viewer);
$v_projects = array();
$is_new = true;
@@ -55,8 +42,7 @@
$crumbs->addTextCrumb(pht('Create Dashboard'));
} else {
- $id = $dashboard->getID();
- $cancel_uri = $this->getApplicationURI('manage/'.$id.'/');
+ $cancel_uri = $dashboard->getURI();
$title = pht('Edit Dashboard: %s', $dashboard->getName());
$header_icon = 'fa-pencil';
@@ -117,9 +103,7 @@
->setContentSourceFromRequest($request)
->applyTransactions($dashboard, $xactions);
- $uri = $this->getApplicationURI('arrange/'.$dashboard->getID().'/');
-
- return id(new AphrontRedirectResponse())->setURI($uri);
+ return id(new AphrontRedirectResponse())->setURI($dashboard->getURI());
} catch (PhabricatorApplicationTransactionValidationException $ex) {
$validation_exception = $ex;
@@ -200,158 +184,6 @@
->appendChild($view);
}
- private function processTemplateRequest(AphrontRequest $request) {
- $viewer = $request->getUser();
-
- $template_control = id(new AphrontFormRadioButtonControl())
- ->setName(pht('template'))
- ->setValue($request->getStr('template', 'empty'))
- ->addButton(
- 'empty',
- pht('Empty'),
- pht('Start with a blank canvas.'))
- ->addButton(
- 'simple',
- pht('Simple Template'),
- pht(
- 'Start with a simple dashboard with a welcome message, a feed of '.
- 'recent events, and a few starter panels.'));
-
- $form = id(new AphrontFormView())
- ->setUser($viewer)
- ->appendRemarkupInstructions(
- pht('Choose a dashboard template to start with.'))
- ->appendChild($template_control);
-
- return $this->newDialog()
- ->setTitle(pht('Create Dashboard'))
- ->setWidth(AphrontDialogView::WIDTH_FORM)
- ->appendChild($form->buildLayoutView())
- ->addCancelButton('/dashboard/')
- ->addSubmitButton(pht('Continue'));
- }
-
- private function processBuildTemplateRequest(AphrontRequest $request) {
- $viewer = $request->getUser();
- $template = $request->getStr('template');
-
- $bare_panel = PhabricatorDashboardPanel::initializeNewPanel($viewer);
- $panel_phids = array();
-
- switch ($template) {
- case 'simple':
- $v_name = pht("%s's Dashboard", $viewer->getUsername());
-
- $welcome_panel = $this->newPanel(
- $request,
- $viewer,
- 'text',
- pht('Welcome'),
- array(
- 'text' => pht(
- "This is a simple template dashboard. You can edit this panel ".
- "to change this text and replace it with a welcome message, or ".
- "leave this placeholder text as-is to give your dashboard a ".
- "rustic, authentic feel.\n\n".
- "You can drag, remove, add, and edit panels to customize the ".
- "rest of this dashboard to show the information you want.\n\n".
- "To install this dashboard on the home page, edit your personal ".
- "or global menu on the homepage and click Dashboard under ".
- "New Menu Item on the right."),
- ));
- $panel_phids[] = $welcome_panel->getPHID();
-
- $feed_panel = $this->newPanel(
- $request,
- $viewer,
- 'query',
- pht('Recent Activity'),
- array(
- 'class' => 'PhabricatorFeedSearchEngine',
- 'key' => 'all',
- ));
- $panel_phids[] = $feed_panel->getPHID();
-
- $revision_panel = $this->newPanel(
- $request,
- $viewer,
- 'query',
- pht('Active Revisions'),
- array(
- 'class' => 'DifferentialRevisionSearchEngine',
- 'key' => 'active',
- ));
- $panel_phids[] = $revision_panel->getPHID();
-
- $task_panel = $this->newPanel(
- $request,
- $viewer,
- 'query',
- pht('Assigned Tasks'),
- array(
- 'class' => 'ManiphestTaskSearchEngine',
- 'key' => 'assigned',
- ));
- $panel_phids[] = $task_panel->getPHID();
-
- $commit_panel = $this->newPanel(
- $request,
- $viewer,
- 'query',
- pht('Recent Commits'),
- array(
- 'class' => 'PhabricatorCommitSearchEngine',
- 'key' => 'all',
- ));
- $panel_phids[] = $commit_panel->getPHID();
-
- $mode_2_and_1 = PhabricatorDashboardLayoutConfig::MODE_THIRDS_AND_THIRD;
- $layout = id(new PhabricatorDashboardLayoutConfig())
- ->setLayoutMode($mode_2_and_1)
- ->setPanelLocation(0, $welcome_panel->getPHID())
- ->setPanelLocation(0, $revision_panel->getPHID())
- ->setPanelLocation(0, $task_panel->getPHID())
- ->setPanelLocation(0, $commit_panel->getPHID())
- ->setPanelLocation(1, $feed_panel->getPHID());
-
- break;
- default:
- throw new Exception(pht('Unknown dashboard template %s!', $template));
- }
-
- // Create the dashboard.
-
- $dashboard = PhabricatorDashboard::initializeNewDashboard($viewer)
- ->setLayoutConfigFromObject($layout);
-
- $xactions = array();
-
- $xactions[] = id(new PhabricatorDashboardTransaction())
- ->setTransactionType(PhabricatorDashboardTransaction::TYPE_NAME)
- ->setNewValue($v_name);
-
- $xactions[] = id(new PhabricatorDashboardTransaction())
- ->setTransactionType(PhabricatorTransactions::TYPE_EDGE)
- ->setMetadataValue(
- 'edge:type',
- PhabricatorDashboardDashboardHasPanelEdgeType::EDGECONST)
- ->setNewValue(
- array(
- '+' => array_fuse($panel_phids),
- ));
-
- $editor = id(new PhabricatorDashboardTransactionEditor())
- ->setActor($viewer)
- ->setContinueOnNoEffect(true)
- ->setContentSourceFromRequest($request)
- ->applyTransactions($dashboard, $xactions);
-
- $manage_uri = $this->getApplicationURI('arrange/'.$dashboard->getID().'/');
-
- return id(new AphrontRedirectResponse())
- ->setURI($manage_uri);
- }
-
private function newPanel(
AphrontRequest $request,
PhabricatorUser $viewer,
@@ -366,7 +198,8 @@
$xactions = array();
$xactions[] = id(new PhabricatorDashboardPanelTransaction())
- ->setTransactionType(PhabricatorDashboardPanelTransaction::TYPE_NAME)
+ ->setTransactionType(
+ PhabricatorDashboardPanelNameTransaction::TRANSACTIONTYPE)
->setNewValue($name);
$editor = id(new PhabricatorDashboardPanelTransactionEditor())
@@ -378,5 +211,4 @@
return $panel;
}
-
}
diff --git a/src/applications/dashboard/controller/dashboard/PhabricatorDashboardInstallController.php b/src/applications/dashboard/controller/dashboard/PhabricatorDashboardInstallController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/dashboard/controller/dashboard/PhabricatorDashboardInstallController.php
@@ -0,0 +1,75 @@
+<?php
+
+final class PhabricatorDashboardInstallController
+ extends PhabricatorDashboardController {
+
+ private $dashboard;
+
+ public function setDashboard(PhabricatorDashboard $dashboard) {
+ $this->dashboard = $dashboard;
+ return $this;
+ }
+
+ public function getDashboard() {
+ return $this->dashboard;
+ }
+
+ public function handleRequest(AphrontRequest $request) {
+ $viewer = $request->getViewer();
+ $id = $request->getURIData('id');
+
+ $dashboard = id(new PhabricatorDashboardQuery())
+ ->setViewer($viewer)
+ ->withIDs(array($id))
+ ->executeOne();
+ if (!$dashboard) {
+ return new Aphront404Response();
+ }
+
+ $this->setDashboard($dashboard);
+ $cancel_uri = $dashboard->getURI();
+
+ $workflow_key = $request->getURIData('workflowKey');
+
+ $workflows = PhabricatorDashboardInstallWorkflow::getAllWorkflows();
+ if (!isset($workflows[$workflow_key])) {
+ return $this->newWorkflowDialog($dashboard, $workflows);
+ }
+
+ return id(clone $workflows[$workflow_key])
+ ->setRequest($request)
+ ->setViewer($viewer)
+ ->setDashboard($dashboard)
+ ->setMode($request->getURIData('modeKey'))
+ ->handleRequest($request);
+ }
+
+ private function newWorkflowDialog(
+ PhabricatorDashboard $dashboard,
+ array $workflows) {
+ $viewer = $this->getViewer();
+ $cancel_uri = $dashboard->getURI();
+
+ $menu = id(new PHUIObjectItemListView())
+ ->setViewer($viewer)
+ ->setFlush(true)
+ ->setBig(true);
+
+ foreach ($workflows as $key => $workflow) {
+ $item = $workflow->getWorkflowMenuItem();
+
+ $item_href = urisprintf('install/%d/%s/', $dashboard->getID(), $key);
+ $item_href = $this->getApplicationURI($item_href);
+ $item->setHref($item_href);
+
+ $menu->addItem($item);
+ }
+
+ return $this->newDialog()
+ ->setTitle(pht('Add Dashboard to Menu'))
+ ->setWidth(AphrontDialogView::WIDTH_FORM)
+ ->appendChild($menu)
+ ->addCancelButton($cancel_uri);
+ }
+
+}
diff --git a/src/applications/dashboard/controller/PhabricatorDashboardManageController.php b/src/applications/dashboard/controller/dashboard/PhabricatorDashboardViewController.php
rename from src/applications/dashboard/controller/PhabricatorDashboardManageController.php
rename to src/applications/dashboard/controller/dashboard/PhabricatorDashboardViewController.php
--- a/src/applications/dashboard/controller/PhabricatorDashboardManageController.php
+++ b/src/applications/dashboard/controller/dashboard/PhabricatorDashboardViewController.php
@@ -1,6 +1,6 @@
<?php
-final class PhabricatorDashboardManageController
+final class PhabricatorDashboardViewController
extends PhabricatorDashboardProfileController {
public function shouldAllowPublic() {
@@ -11,10 +11,6 @@
$viewer = $request->getViewer();
$id = $request->getURIData('id');
- // TODO: This UI should drop a lot of capabilities if the user can't
- // edit the dashboard, but we should still let them in for "Install" and
- // "View History".
-
$dashboard = id(new PhabricatorDashboardQuery())
->setViewer($viewer)
->withIDs(array($id))
@@ -31,44 +27,38 @@
PhabricatorPolicyCapability::CAN_EDIT);
$title = $dashboard->getName();
-
$crumbs = $this->buildApplicationCrumbs();
- $crumbs->addTextCrumb(pht('Manage'));
-
$header = $this->buildHeaderView();
+
$curtain = $this->buildCurtainView($dashboard);
- $properties = $this->buildPropertyView($dashboard);
$timeline = $this->buildTransactionTimeline(
$dashboard,
new PhabricatorDashboardTransactionQuery());
$timeline->setShouldTerminate(true);
- $info_view = null;
- if (!$can_edit) {
- $no_edit = pht(
- 'You do not have permission to edit this dashboard.');
+ $rendered_dashboard = id(new PhabricatorDashboardRenderingEngine())
+ ->setViewer($viewer)
+ ->setDashboard($dashboard)
+ ->setArrangeMode($can_edit)
+ ->renderDashboard();
- $info_view = id(new PHUIInfoView())
- ->setSeverity(PHUIInfoView::SEVERITY_NOTICE)
- ->setErrors(array($no_edit));
- }
+ $dashboard_box = id(new PHUIBoxView())
+ ->addClass('dashboard-preview-box')
+ ->appendChild($rendered_dashboard);
$view = id(new PHUITwoColumnView())
->setHeader($header)
->setCurtain($curtain)
- ->setMainColumn(array(
- $info_view,
- $properties,
- $timeline,
- ));
-
- $navigation = $this->buildSideNavView('manage');
+ ->setMainColumn(
+ array(
+ $dashboard_box,
+ $timeline,
+ ));
return $this->newPage()
->setTitle($title)
->setCrumbs($crumbs)
- ->setNavigation($navigation)
->appendChild($view);
}
@@ -89,7 +79,15 @@
->setName(pht('Edit Dashboard'))
->setIcon('fa-pencil')
->setHref($this->getApplicationURI("edit/{$id}/"))
- ->setDisabled(!$can_edit));
+ ->setDisabled(!$can_edit)
+ ->setWorkflow(!$can_edit));
+
+ $curtain->addAction(
+ id(new PhabricatorActionView())
+ ->setName(pht('Add Dashboard to Menu'))
+ ->setIcon('fa-wrench')
+ ->setHref($this->getApplicationURI("/install/{$id}/"))
+ ->setWorkflow(true));
if ($dashboard->isArchived()) {
$curtain->addAction(
@@ -98,7 +96,7 @@
->setIcon('fa-check')
->setHref($this->getApplicationURI("archive/{$id}/"))
->setDisabled(!$can_edit)
- ->setWorkflow($can_edit));
+ ->setWorkflow(true));
} else {
$curtain->addAction(
id(new PhabricatorActionView())
@@ -106,34 +104,11 @@
->setIcon('fa-ban')
->setHref($this->getApplicationURI("archive/{$id}/"))
->setDisabled(!$can_edit)
- ->setWorkflow($can_edit));
+ ->setWorkflow(true));
}
return $curtain;
}
- private function buildPropertyView(PhabricatorDashboard $dashboard) {
- $viewer = $this->getViewer();
-
- $properties = id(new PHUIPropertyListView())
- ->setUser($viewer);
-
- $descriptions = PhabricatorPolicyQuery::renderPolicyDescriptions(
- $viewer,
- $dashboard);
-
- $properties->addProperty(
- pht('Editable By'),
- $descriptions[PhabricatorPolicyCapability::CAN_EDIT]);
-
- $properties->addProperty(
- pht('Panels'),
- $viewer->renderHandleList($dashboard->getPanelPHIDs()));
-
- return id(new PHUIObjectBoxView())
- ->setHeaderText(pht('Details'))
- ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
- ->addPropertyList($properties);
- }
}
diff --git a/src/applications/dashboard/controller/PhabricatorDashboardPanelArchiveController.php b/src/applications/dashboard/controller/panel/PhabricatorDashboardPanelArchiveController.php
rename from src/applications/dashboard/controller/PhabricatorDashboardPanelArchiveController.php
rename to src/applications/dashboard/controller/panel/PhabricatorDashboardPanelArchiveController.php
--- a/src/applications/dashboard/controller/PhabricatorDashboardPanelArchiveController.php
+++ b/src/applications/dashboard/controller/panel/PhabricatorDashboardPanelArchiveController.php
@@ -25,7 +25,8 @@
if ($request->isFormPost()) {
$xactions = array();
$xactions[] = id(new PhabricatorDashboardPanelTransaction())
- ->setTransactionType(PhabricatorDashboardPanelTransaction::TYPE_ARCHIVE)
+ ->setTransactionType(
+ PhabricatorDashboardPanelStatusTransaction::TRANSACTIONTYPE)
->setNewValue((int)!$panel->getIsArchived());
id(new PhabricatorDashboardPanelTransactionEditor())
diff --git a/src/applications/dashboard/controller/panel/PhabricatorDashboardPanelEditController.php b/src/applications/dashboard/controller/panel/PhabricatorDashboardPanelEditController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/dashboard/controller/panel/PhabricatorDashboardPanelEditController.php
@@ -0,0 +1,98 @@
+<?php
+
+final class PhabricatorDashboardPanelEditController
+ extends PhabricatorDashboardController {
+
+ public function handleRequest(AphrontRequest $request) {
+ $viewer = $this->getViewer();
+
+ $engine = id(new PhabricatorDashboardPanelEditEngine())
+ ->setController($this);
+
+ // We can create or edit a panel in the context of a dashboard. If we
+ // started on a dashboard, we want to return to that dashboard when we're
+ // done editing.
+ $dashboard_id = $request->getStr('dashboardID');
+ if (strlen($dashboard_id)) {
+ $dashboard = id(new PhabricatorDashboardQuery())
+ ->setViewer($viewer)
+ ->withIDs(array($dashboard_id))
+ ->requireCapabilities(
+ array(
+ PhabricatorPolicyCapability::CAN_VIEW,
+ PhabricatorPolicyCapability::CAN_EDIT,
+ ))
+ ->executeOne();
+ if (!$dashboard) {
+ return new Aphront404Response();
+ }
+
+ $engine
+ ->setDashboard($dashboard)
+ ->addContextParameter('dashboardID', $dashboard_id);
+ } else {
+ $dashboard = null;
+ }
+
+ $id = $request->getURIData('id');
+ if (!$id) {
+ $column_id = $request->getStr('columnID');
+
+ if ($dashboard) {
+ $cancel_uri = $dashboard->getURI();
+ } else {
+ $cancel_uri = $this->getApplicationURI('panel/');
+ }
+
+ $panel_type = $request->getStr('panelType');
+ $panel_types = PhabricatorDashboardPanelType::getAllPanelTypes();
+ if (empty($panel_types[$panel_type])) {
+ return $this->buildPanelTypeResponse($cancel_uri);
+ }
+
+ $engine
+ ->addContextParameter('panelType', $panel_type)
+ ->addContextParameter('columnID', $column_id)
+ ->setPanelType($panel_type)
+ ->setColumnID($column_id);
+ }
+
+ return $engine->buildResponse();
+ }
+
+ private function buildPanelTypeResponse($cancel_uri) {
+ $viewer = $this->getViewer();
+ $request = $this->getRequest();
+
+ $base_uri = $request->getRequestURI();
+ $base_uri = new PhutilURI($base_uri);
+
+ $menu = id(new PHUIObjectItemListView())
+ ->setViewer($viewer)
+ ->setFlush(true)
+ ->setBig(true);
+
+ $panel_types = PhabricatorDashboardPanelType::getAllPanelTypes();
+ foreach ($panel_types as $panel_type) {
+ $item = id(new PHUIObjectItemView())
+ ->setClickable(true)
+ ->setImageIcon($panel_type->getIcon())
+ ->setHeader($panel_type->getPanelTypeName())
+ ->addAttribute($panel_type->getPanelTypeDescription());
+
+ $type_uri = id(clone $base_uri)
+ ->replaceQueryParam('panelType', $panel_type->getPanelTypeKey());
+
+ $item->setHref($type_uri);
+
+ $menu->addItem($item);
+ }
+
+ return $this->newDialog()
+ ->setTitle(pht('Choose Panel Type'))
+ ->setWidth(AphrontDialogView::WIDTH_FORM)
+ ->appendChild($menu)
+ ->addCancelButton($cancel_uri);
+ }
+
+}
diff --git a/src/applications/dashboard/controller/PhabricatorDashboardPanelListController.php b/src/applications/dashboard/controller/panel/PhabricatorDashboardPanelListController.php
rename from src/applications/dashboard/controller/PhabricatorDashboardPanelListController.php
rename to src/applications/dashboard/controller/panel/PhabricatorDashboardPanelListController.php
--- a/src/applications/dashboard/controller/PhabricatorDashboardPanelListController.php
+++ b/src/applications/dashboard/controller/panel/PhabricatorDashboardPanelListController.php
@@ -43,7 +43,7 @@
id(new PHUIListItemView())
->setIcon('fa-plus-square')
->setName(pht('Create Panel'))
- ->setHref($this->getApplicationURI().'panel/create/'));
+ ->setHref($this->getApplicationURI().'panel/edit/'));
return $crumbs;
}
@@ -52,7 +52,7 @@
$create_button = id(new PHUIButtonView())
->setTag('a')
->setText(pht('Create a Panel'))
- ->setHref('/dashboard/panel/create/')
+ ->setHref('/dashboard/panel/edit/')
->setColor(PHUIButtonView::GREEN);
$icon = $this->getApplication()->getIcon();
diff --git a/src/applications/dashboard/controller/PhabricatorDashboardPanelRenderController.php b/src/applications/dashboard/controller/panel/PhabricatorDashboardPanelRenderController.php
rename from src/applications/dashboard/controller/PhabricatorDashboardPanelRenderController.php
rename to src/applications/dashboard/controller/panel/PhabricatorDashboardPanelRenderController.php
diff --git a/src/applications/dashboard/controller/panel/PhabricatorDashboardPanelTabsController.php b/src/applications/dashboard/controller/panel/PhabricatorDashboardPanelTabsController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/dashboard/controller/panel/PhabricatorDashboardPanelTabsController.php
@@ -0,0 +1,295 @@
+<?php
+
+final class PhabricatorDashboardPanelTabsController
+ extends PhabricatorDashboardController {
+
+ public function handleRequest(AphrontRequest $request) {
+ $viewer = $this->getViewer();
+
+ $panel = id(new PhabricatorDashboardPanelQuery())
+ ->setViewer($viewer)
+ ->withIDs(array($request->getURIData('id')))
+ ->requireCapabilities(
+ array(
+ PhabricatorPolicyCapability::CAN_VIEW,
+ PhabricatorPolicyCapability::CAN_EDIT,
+ ))
+ ->executeOne();
+ if (!$panel) {
+ return new Aphront404Response();
+ }
+
+ $tabs_type = id(new PhabricatorDashboardTabsPanelType())
+ ->getPanelTypeKey();
+
+ // This controller may only be used to edit tab panels.
+ $panel_type = $panel->getPanelType();
+ if ($panel_type !== $tabs_type) {
+ return new Aphront404Response();
+ }
+
+ $op = $request->getURIData('op');
+ $after = $request->getStr('after');
+ if (!strlen($after)) {
+ $after = null;
+ }
+
+ $target = $request->getStr('target');
+ if (!strlen($target)) {
+ $target = null;
+ }
+
+ $impl = $panel->getImplementation();
+ $config = $impl->getPanelConfiguration($panel);
+
+ $cancel_uri = $panel->getURI();
+
+ if ($after !== null) {
+ $found = false;
+ foreach ($config as $key => $spec) {
+ if ((string)$key === $after) {
+ $found = true;
+ break;
+ }
+ }
+
+ if (!$found) {
+ return $this->newDialog()
+ ->setTitle(pht('Adjacent Tab Not Found'))
+ ->appendParagraph(
+ pht(
+ 'Adjacent tab ("%s") was not found on this panel. It may have '.
+ 'been removed.',
+ $after))
+ ->addCancelButton($cancel_uri);
+ }
+ }
+
+ if ($target !== null) {
+ $found = false;
+ foreach ($config as $key => $spec) {
+ if ((string)$key === $target) {
+ $found = true;
+ break;
+ }
+ }
+
+ if (!$found) {
+ return $this->newDialog()
+ ->setTitle(pht('Target Tab Not Found'))
+ ->appendParagraph(
+ pht(
+ 'Target tab ("%s") was not found on this panel. It may have '.
+ 'been removed.',
+ $target))
+ ->addCancelButton($cancel_uri);
+ }
+ }
+
+ switch ($op) {
+ case 'add':
+ return $this->handleAddOperation($panel, $after, $cancel_uri);
+ case 'remove':
+ return $this->handleRemoveOperation($panel, $target, $cancel_uri);
+ case 'move':
+ break;
+ case 'rename':
+ return $this->handleRenameOperation($panel, $target, $cancel_uri);
+ }
+ }
+
+ private function handleAddOperation(
+ PhabricatorDashboardPanel $panel,
+ $after,
+ $cancel_uri) {
+ $request = $this->getRequest();
+ $viewer = $this->getViewer();
+
+ $panel_phid = null;
+ $errors = array();
+ if ($request->isFormPost()) {
+ $panel_phid = $request->getArr('panelPHID');
+ $panel_phid = head($panel_phid);
+
+ $add_panel = id(new PhabricatorDashboardPanelQuery())
+ ->setViewer($viewer)
+ ->withPHIDs(array($panel_phid))
+ ->executeOne();
+ if (!$add_panel) {
+ $errors[] = pht('You must select a valid panel.');
+ }
+
+ if (!$errors) {
+ $add_panel_config = array(
+ 'name' => null,
+ 'panelID' => $add_panel->getID(),
+ );
+ $add_panel_key = Filesystem::readRandomCharacters(12);
+
+ $impl = $panel->getImplementation();
+ $old_config = $impl->getPanelConfiguration($panel);
+ $new_config = array();
+ if ($after === null) {
+ $new_config = $old_config;
+ $new_config[] = $add_panel_config;
+ } else {
+ foreach ($old_config as $key => $value) {
+ $new_config[$key] = $value;
+ if ((string)$key === $after) {
+ $new_config[$add_panel_key] = $add_panel_config;
+ }
+ }
+ }
+
+ $xactions = array();
+
+ $xactions[] = $panel->getApplicationTransactionTemplate()
+ ->setTransactionType(
+ PhabricatorDashboardTabsPanelTabsTransaction::TRANSACTIONTYPE)
+ ->setNewValue($new_config);
+
+ $editor = id(new PhabricatorDashboardPanelTransactionEditor())
+ ->setContentSourceFromRequest($request)
+ ->setActor($viewer)
+ ->setContinueOnNoEffect(true)
+ ->setContinueOnMissingFields(true);
+
+ $editor->applyTransactions($panel, $xactions);
+
+ return id(new AphrontRedirectResponse())->setURI($cancel_uri);
+ }
+ }
+
+ if ($panel_phid) {
+ $v_panel = array($panel_phid);
+ } else {
+ $v_panel = array();
+ }
+
+ $form = id(new AphrontFormView())
+ ->setViewer($viewer)
+ ->appendControl(
+ id(new AphrontFormTokenizerControl())
+ ->setDatasource(new PhabricatorDashboardPanelDatasource())
+ ->setLimit(1)
+ ->setName('panelPHID')
+ ->setLabel(pht('Panel'))
+ ->setValue($v_panel));
+
+ return $this->newDialog()
+ ->setTitle(pht('Choose Dashboard Panel'))
+ ->setErrors($errors)
+ ->setWidth(AphrontDialogView::WIDTH_FORM)
+ ->addHiddenInput('after', $after)
+ ->appendForm($form)
+ ->addCancelButton($cancel_uri)
+ ->addSubmitButton(pht('Add Panel'));
+ }
+
+ private function handleRemoveOperation(
+ PhabricatorDashboardPanel $panel,
+ $target,
+ $cancel_uri) {
+ $request = $this->getRequest();
+ $viewer = $this->getViewer();
+
+ $panel_phid = null;
+ $errors = array();
+ if ($request->isFormPost()) {
+ $impl = $panel->getImplementation();
+ $old_config = $impl->getPanelConfiguration($panel);
+
+ $new_config = $this->removePanel($old_config, $target);
+ $this->writePanelConfig($panel, $new_config);
+
+ return id(new AphrontRedirectResponse())->setURI($cancel_uri);
+ }
+
+ return $this->newDialog()
+ ->setTitle(pht('Remove tab?'))
+ ->addHiddenInput('target', $target)
+ ->appendParagraph(pht('Really remove this tab?'))
+ ->addCancelButton($cancel_uri)
+ ->addSubmitButton(pht('Remove Tab'));
+ }
+
+ private function handleRenameOperation(
+ PhabricatorDashboardPanel $panel,
+ $target,
+ $cancel_uri) {
+ $request = $this->getRequest();
+ $viewer = $this->getViewer();
+
+ $impl = $panel->getImplementation();
+ $old_config = $impl->getPanelConfiguration($panel);
+
+ $spec = $old_config[$target];
+ $name = idx($spec, 'name');
+
+ if ($request->isFormPost()) {
+ $name = $request->getStr('name');
+
+ $new_config = $this->renamePanel($old_config, $target, $name);
+ $this->writePanelConfig($panel, $new_config);
+
+ return id(new AphrontRedirectResponse())->setURI($cancel_uri);
+ }
+
+ $form = id(new AphrontFormView())
+ ->setViewer($viewer)
+ ->appendControl(
+ id(new AphrontFormTextControl())
+ ->setValue($name)
+ ->setName('name')
+ ->setLabel(pht('Tab Name')));
+
+ return $this->newDialog()
+ ->setTitle(pht('Rename Panel'))
+ ->addHiddenInput('target', $target)
+ ->appendForm($form)
+ ->addCancelButton($cancel_uri)
+ ->addSubmitButton(pht('Rename Tab'));
+ }
+
+
+ private function writePanelConfig(
+ PhabricatorDashboardPanel $panel,
+ array $config) {
+ $request = $this->getRequest();
+ $viewer = $this->getViewer();
+
+ $xactions = array();
+
+ $xactions[] = $panel->getApplicationTransactionTemplate()
+ ->setTransactionType(
+ PhabricatorDashboardTabsPanelTabsTransaction::TRANSACTIONTYPE)
+ ->setNewValue($config);
+
+ $editor = id(new PhabricatorDashboardPanelTransactionEditor())
+ ->setContentSourceFromRequest($request)
+ ->setActor($viewer)
+ ->setContinueOnNoEffect(true)
+ ->setContinueOnMissingFields(true);
+
+ return $editor->applyTransactions($panel, $xactions);
+ }
+
+ private function removePanel(array $config, $target) {
+ $result = array();
+
+ foreach ($config as $key => $panel_spec) {
+ if ((string)$key === $target) {
+ continue;
+ }
+ $result[$key] = $panel_spec;
+ }
+
+ return $result;
+ }
+
+ private function renamePanel(array $config, $target, $name) {
+ $config[$target]['name'] = $name;
+ return $config;
+ }
+
+}
diff --git a/src/applications/dashboard/controller/PhabricatorDashboardPanelViewController.php b/src/applications/dashboard/controller/panel/PhabricatorDashboardPanelViewController.php
rename from src/applications/dashboard/controller/PhabricatorDashboardPanelViewController.php
rename to src/applications/dashboard/controller/panel/PhabricatorDashboardPanelViewController.php
diff --git a/src/applications/dashboard/customfield/PhabricatorDashboardPanelCoreCustomField.php b/src/applications/dashboard/customfield/PhabricatorDashboardPanelCoreCustomField.php
deleted file mode 100644
--- a/src/applications/dashboard/customfield/PhabricatorDashboardPanelCoreCustomField.php
+++ /dev/null
@@ -1,47 +0,0 @@
-<?php
-
-final class PhabricatorDashboardPanelCoreCustomField
- extends PhabricatorDashboardPanelCustomField
- implements PhabricatorStandardCustomFieldInterface {
-
- public function getStandardCustomFieldNamespace() {
- return 'dashboard:core';
- }
-
- public function createFields($object) {
- if (!$object->getPanelType()) {
- return array();
- }
-
- $impl = $object->requireImplementation();
- $specs = $impl->getFieldSpecifications();
- return PhabricatorStandardCustomField::buildStandardFields($this, $specs);
- }
-
- public function shouldUseStorage() {
- return false;
- }
-
- public function readValueFromObject(PhabricatorCustomFieldInterface $object) {
- $key = $this->getProxy()->getRawStandardFieldKey();
- $this->setValueFromStorage($object->getProperty($key));
- $this->didSetValueFromStorage();
- }
-
- public function applyApplicationTransactionInternalEffects(
- PhabricatorApplicationTransaction $xaction) {
- $object = $this->getObject();
- $key = $this->getProxy()->getRawStandardFieldKey();
-
- $this->setValueFromApplicationTransactions($xaction->getNewValue());
- $value = $this->getValueForStorage();
-
- $object->setProperty($key, $value);
- }
-
- public function applyApplicationTransactionExternalEffects(
- PhabricatorApplicationTransaction $xaction) {
- return;
- }
-
-}
diff --git a/src/applications/dashboard/customfield/PhabricatorDashboardPanelCustomField.php b/src/applications/dashboard/customfield/PhabricatorDashboardPanelCustomField.php
deleted file mode 100644
--- a/src/applications/dashboard/customfield/PhabricatorDashboardPanelCustomField.php
+++ /dev/null
@@ -1,4 +0,0 @@
-<?php
-
-abstract class PhabricatorDashboardPanelCustomField
- extends PhabricatorCustomField {}
diff --git a/src/applications/dashboard/customfield/PhabricatorDashboardPanelTabsCustomField.php b/src/applications/dashboard/customfield/PhabricatorDashboardPanelTabsCustomField.php
deleted file mode 100644
--- a/src/applications/dashboard/customfield/PhabricatorDashboardPanelTabsCustomField.php
+++ /dev/null
@@ -1,114 +0,0 @@
-<?php
-
-final class PhabricatorDashboardPanelTabsCustomField
- extends PhabricatorStandardCustomField {
-
- public function getFieldType() {
- return 'dashboard.tabs';
- }
-
- public function shouldAppearInApplicationSearch() {
- return false;
- }
-
- public function readValueFromRequest(AphrontRequest $request) {
- $value = array();
-
- $names = $request->getArr($this->getFieldKey().'_name');
- $panel_ids = $request->getArr($this->getFieldKey().'_panelID');
- $panels = array();
- foreach ($panel_ids as $panel_id) {
- $panels[] = $panel_id[0];
- }
- foreach ($names as $idx => $name) {
- $panel_id = idx($panels, $idx);
- if (strlen($name) && $panel_id) {
- $value[] = array(
- 'name' => $name,
- 'panelID' => $panel_id,
- );
- }
- }
-
- $this->setFieldValue($value);
- }
-
- public function getApplicationTransactionTitle(
- PhabricatorApplicationTransaction $xaction) {
- $author_phid = $xaction->getAuthorPHID();
- $old = $xaction->getOldValue();
- $new = $xaction->getNewValue();
-
- $new_tabs = array();
- if ($new) {
- foreach ($new as $new_tab) {
- $new_tabs[] = $new_tab['name'];
- }
- $new_tabs = implode(' | ', $new_tabs);
- }
-
- $old_tabs = array();
- if ($old) {
- foreach ($old as $old_tab) {
- $old_tabs[] = $old_tab['name'];
- }
- $old_tabs = implode(' | ', $old_tabs);
- }
-
- if (!$old) {
- // In case someone makes a tab panel with no tabs.
- if ($new) {
- return pht(
- '%s set the tabs to "%s".',
- $xaction->renderHandleLink($author_phid),
- $new_tabs);
- }
- } else if (!$new) {
- return pht(
- '%s removed tabs.',
- $xaction->renderHandleLink($author_phid));
- } else {
- return pht(
- '%s changed the tabs from "%s" to "%s".',
- $xaction->renderHandleLink($author_phid),
- $old_tabs,
- $new_tabs);
- }
- }
-
- public function renderEditControl(array $handles) {
- // NOTE: This includes archived panels so we don't mutate the tabs
- // when saving a tab panel that includes archived panels. This whole UI is
- // hopefully temporary anyway.
-
- $value = $this->getFieldValue();
- if (!is_array($value)) {
- $value = array();
- }
-
- $out = array();
- for ($ii = 1; $ii <= 6; $ii++) {
- $tab = idx($value, ($ii - 1), array());
- $panel = idx($tab, 'panelID', null);
- $panel_id = array();
- if ($panel) {
- $panel_id[] = $panel;
- }
- $out[] = id(new AphrontFormTextControl())
- ->setName($this->getFieldKey().'_name[]')
- ->setValue(idx($tab, 'name'))
- ->setLabel(pht('Tab %d Name', $ii));
-
- $out[] = id(new AphrontFormTokenizerControl())
- ->setUser($this->getViewer())
- ->setDatasource(new PhabricatorDashboardPanelDatasource())
- ->setName($this->getFieldKey().'_panelID[]')
- ->setValue($panel_id)
- ->setLimit(1)
- ->setLabel(pht('Tab %d Panel', $ii));
- }
-
- return $out;
- }
-
-}
diff --git a/src/applications/dashboard/customfield/PhabricatorDashboardPanelSearchApplicationCustomField.php b/src/applications/dashboard/editfield/PhabricatorDashboardQueryPanelApplicationEditField.php
rename from src/applications/dashboard/customfield/PhabricatorDashboardPanelSearchApplicationCustomField.php
rename to src/applications/dashboard/editfield/PhabricatorDashboardQueryPanelApplicationEditField.php
--- a/src/applications/dashboard/customfield/PhabricatorDashboardPanelSearchApplicationCustomField.php
+++ b/src/applications/dashboard/editfield/PhabricatorDashboardQueryPanelApplicationEditField.php
@@ -1,17 +1,11 @@
<?php
-final class PhabricatorDashboardPanelSearchApplicationCustomField
- extends PhabricatorStandardCustomField {
+final class PhabricatorDashboardQueryPanelApplicationEditField
+ extends PhabricatorEditField {
- public function getFieldType() {
- return 'search.application';
- }
-
- public function shouldAppearInApplicationSearch() {
- return false;
- }
+ private $controlID;
- public function renderEditControl(array $handles) {
+ protected function newControl() {
$engines = id(new PhutilClassMapQuery())
->setAncestorClass('PhabricatorApplicationSearchEngine')
->setFilterMethod('canUseInPanelContext')
@@ -31,7 +25,7 @@
$options = array();
- $value = $this->getFieldValue();
+ $value = $this->getValueForControl();
if (strlen($value) && empty($engines[$value])) {
$options[$value] = $value;
}
@@ -42,12 +36,24 @@
}
return id(new AphrontFormSelectControl())
- ->setID($this->getFieldControlID())
- ->setLabel($this->getFieldName())
- ->setCaption($this->getCaption())
- ->setName($this->getFieldKey())
- ->setValue($this->getFieldValue())
+ ->setID($this->getControlID())
->setOptions($options);
}
+ protected function newHTTPParameterType() {
+ return new AphrontSelectHTTPParameterType();
+ }
+
+ public function getControlID() {
+ if (!$this->controlID) {
+ $this->controlID = celerity_generate_unique_node_id();
+ }
+
+ return $this->controlID;
+ }
+
+ protected function newConduitParameterType() {
+ return new ConduitStringParameterType();
+ }
+
}
diff --git a/src/applications/dashboard/customfield/PhabricatorDashboardPanelSearchQueryCustomField.php b/src/applications/dashboard/editfield/PhabricatorDashboardQueryPanelQueryEditField.php
rename from src/applications/dashboard/customfield/PhabricatorDashboardPanelSearchQueryCustomField.php
rename to src/applications/dashboard/editfield/PhabricatorDashboardQueryPanelQueryEditField.php
--- a/src/applications/dashboard/customfield/PhabricatorDashboardPanelSearchQueryCustomField.php
+++ b/src/applications/dashboard/editfield/PhabricatorDashboardQueryPanelQueryEditField.php
@@ -1,23 +1,26 @@
<?php
-final class PhabricatorDashboardPanelSearchQueryCustomField
- extends PhabricatorStandardCustomField {
+final class PhabricatorDashboardQueryPanelQueryEditField
+ extends PhabricatorEditField {
- public function getFieldType() {
- return 'search.query';
+ private $applicationControlID;
+
+ public function setApplicationControlID($id) {
+ $this->applicationControlID = $id;
+ return $this;
}
- public function shouldAppearInApplicationSearch() {
- return false;
+ public function getApplicationControlID() {
+ return $this->applicationControlID;
}
- public function renderEditControl(array $handles) {
+ protected function newControl() {
$engines = id(new PhutilClassMapQuery())
->setAncestorClass('PhabricatorApplicationSearchEngine')
->setFilterMethod('canUseInPanelContext')
->execute();
- $value = $this->getFieldValue();
+ $value = $this->getValueForControl();
$queries = array();
$seen = false;
@@ -43,12 +46,14 @@
$options = array($value => $name);
- $app_control_key = $this->getFieldConfigValue('control.application');
+ $application_id = $this->getApplicationControlID();
+ $control_id = celerity_generate_unique_node_id();
+
Javelin::initBehavior(
'dashboard-query-panel-select',
array(
- 'applicationID' => $this->getFieldControlID($app_control_key),
- 'queryID' => $this->getFieldControlID(),
+ 'applicationID' => $application_id,
+ 'queryID' => $control_id,
'options' => $queries,
'value' => array(
'key' => strlen($value) ? $value : null,
@@ -57,12 +62,16 @@
));
return id(new AphrontFormSelectControl())
- ->setID($this->getFieldControlID())
- ->setLabel($this->getFieldName())
- ->setCaption($this->getCaption())
- ->setName($this->getFieldKey())
- ->setValue($this->getFieldValue())
+ ->setID($control_id)
->setOptions($options);
}
+ protected function newHTTPParameterType() {
+ return new AphrontSelectHTTPParameterType();
+ }
+
+ protected function newConduitParameterType() {
+ return new ConduitStringParameterType();
+ }
+
}
diff --git a/src/applications/dashboard/editor/PhabricatorDashboardPanelEditEngine.php b/src/applications/dashboard/editor/PhabricatorDashboardPanelEditEngine.php
--- a/src/applications/dashboard/editor/PhabricatorDashboardPanelEditEngine.php
+++ b/src/applications/dashboard/editor/PhabricatorDashboardPanelEditEngine.php
@@ -6,6 +6,8 @@
const ENGINECONST = 'dashboard.panel';
private $panelType;
+ private $dashboard;
+ private $columnID;
public function setPanelType($panel_type) {
$this->panelType = $panel_type;
@@ -16,6 +18,24 @@
return $this->panelType;
}
+ public function setDashboard(PhabricatorDashboard $dashboard) {
+ $this->dashboard = $dashboard;
+ return $this;
+ }
+
+ public function getDashboard() {
+ return $this->dashboard;
+ }
+
+ public function setColumnID($column_id) {
+ $this->columnID = $column_id;
+ return $this;
+ }
+
+ public function getColumnID() {
+ return $this->columnID;
+ }
+
public function isEngineConfigurable() {
return false;
}
@@ -63,6 +83,33 @@
return pht('Create Panel');
}
+ protected function getObjectCreateCancelURI($object) {
+ $dashboard = $this->getDashboard();
+ if ($dashboard) {
+ return $dashboard->getURI();
+ }
+
+ return parent::getObjectCreateCancelURI($object);
+ }
+
+ public function getEffectiveObjectEditDoneURI($object) {
+ $dashboard = $this->getDashboard();
+ if ($dashboard) {
+ return $dashboard->getURI();
+ }
+
+ return parent::getEffectiveObjectEditDoneURI($object);
+ }
+
+ protected function getObjectEditCancelURI($object) {
+ $dashboard = $this->getDashboard();
+ if ($dashboard) {
+ return $dashboard->getURI();
+ }
+
+ return parent::getObjectEditCancelURI($object);
+ }
+
protected function getObjectEditTitleText($object) {
return pht('Edit Panel: %s', $object->getName());
}
@@ -83,18 +130,42 @@
return $object->getURI();
}
+ protected function didApplyTransactions($object, array $xactions) {
+ $dashboard = $this->getDashboard();
+ if ($dashboard) {
+ $viewer = $this->getViewer();
+ $controller = $this->getController();
+ $request = $controller->getRequest();
+
+ PhabricatorDashboardTransactionEditor::addPanelToDashboard(
+ $viewer,
+ PhabricatorContentSource::newFromRequest($request),
+ $object,
+ $dashboard,
+ (int)$this->getColumnID());
+ }
+ }
+
protected function buildCustomEditFields($object) {
- return array(
+ $fields = array(
id(new PhabricatorTextEditField())
->setKey('name')
->setLabel(pht('Name'))
->setDescription(pht('Name of the panel.'))
->setConduitDescription(pht('Rename the panel.'))
->setConduitTypeDescription(pht('New panel name.'))
- ->setTransactionType(PhabricatorDashboardPanelTransaction::TYPE_NAME)
+ ->setTransactionType(
+ PhabricatorDashboardPanelNameTransaction::TRANSACTIONTYPE)
->setIsRequired(true)
->setValue($object->getName()),
);
+
+ $panel_fields = $object->getEditEngineFields();
+ foreach ($panel_fields as $panel_field) {
+ $fields[] = $panel_field;
+ }
+
+ return $fields;
}
}
diff --git a/src/applications/dashboard/editor/PhabricatorDashboardPanelTransactionEditor.php b/src/applications/dashboard/editor/PhabricatorDashboardPanelTransactionEditor.php
--- a/src/applications/dashboard/editor/PhabricatorDashboardPanelTransactionEditor.php
+++ b/src/applications/dashboard/editor/PhabricatorDashboardPanelTransactionEditor.php
@@ -18,96 +18,7 @@
$types[] = PhabricatorTransactions::TYPE_EDIT_POLICY;
$types[] = PhabricatorTransactions::TYPE_EDGE;
- $types[] = PhabricatorDashboardPanelTransaction::TYPE_NAME;
- $types[] = PhabricatorDashboardPanelTransaction::TYPE_ARCHIVE;
-
return $types;
}
- protected function getCustomTransactionOldValue(
- PhabricatorLiskDAO $object,
- PhabricatorApplicationTransaction $xaction) {
- switch ($xaction->getTransactionType()) {
- case PhabricatorDashboardPanelTransaction::TYPE_NAME:
- if ($this->getIsNewObject()) {
- return null;
- }
- return $object->getName();
- case PhabricatorDashboardPanelTransaction::TYPE_ARCHIVE:
- return (int)$object->getIsArchived();
- }
-
- return parent::getCustomTransactionOldValue($object, $xaction);
- }
-
- protected function getCustomTransactionNewValue(
- PhabricatorLiskDAO $object,
- PhabricatorApplicationTransaction $xaction) {
- switch ($xaction->getTransactionType()) {
- case PhabricatorDashboardPanelTransaction::TYPE_NAME:
- return $xaction->getNewValue();
- case PhabricatorDashboardPanelTransaction::TYPE_ARCHIVE:
- return (int)$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 PhabricatorDashboardPanelTransaction::TYPE_ARCHIVE:
- $object->setIsArchived((int)$xaction->getNewValue());
- return;
- }
-
- return parent::applyCustomInternalTransaction($object, $xaction);
- }
-
- protected function applyCustomExternalTransaction(
- PhabricatorLiskDAO $object,
- PhabricatorApplicationTransaction $xaction) {
-
- switch ($xaction->getTransactionType()) {
- case PhabricatorDashboardPanelTransaction::TYPE_NAME:
- case PhabricatorDashboardPanelTransaction::TYPE_ARCHIVE:
- 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/engine/PhabricatorDashboardPanelRenderingEngine.php b/src/applications/dashboard/engine/PhabricatorDashboardPanelRenderingEngine.php
--- a/src/applications/dashboard/engine/PhabricatorDashboardPanelRenderingEngine.php
+++ b/src/applications/dashboard/engine/PhabricatorDashboardPanelRenderingEngine.php
@@ -14,6 +14,7 @@
private $headerMode = self::HEADER_MODE_NORMAL;
private $dashboardID;
private $movable = true;
+ private $panelHandle;
public function setDashboardID($id) {
$this->dashboardID = $id;
@@ -33,6 +34,19 @@
return $this->headerMode;
}
+ public function setPanelHandle(PhabricatorObjectHandle $panel_handle) {
+ $this->panelHandle = $panel_handle;
+ return $this;
+ }
+
+ public function getPanelHandle() {
+ return $this->panelHandle;
+ }
+
+ public function isEditMode() {
+ return ($this->getHeaderMode() === self::HEADER_MODE_EDIT);
+ }
+
/**
* Allow the engine to render the panel via Ajax.
*/
@@ -90,11 +104,19 @@
$panel = $this->getPanel();
if (!$panel) {
- return $this->renderErrorPanel(
- pht('Missing or Restricted Panel'),
- pht(
- 'This panel does not exist, or you do not have permission '.
- 'to see it.'));
+ $handle = $this->getPanelHandle();
+ if ($handle->getPolicyFiltered()) {
+ return $this->renderErrorPanel(
+ pht('Restricted Panel'),
+ pht(
+ 'You do not have permission to see this panel.'));
+ } else {
+ return $this->renderErrorPanel(
+ pht('Invalid Panel'),
+ pht(
+ 'This panel is invalid or does not exist. It may have been '.
+ 'deleted.'));
+ }
}
$panel_type = $panel->getImplementation();
@@ -185,12 +207,13 @@
->setHeader($title);
break;
}
+
$icon = id(new PHUIIconView())
->setIcon('fa-warning red msr');
$content = id(new PHUIBoxView())
->addClass('dashboard-box')
- ->addMargin(PHUI::MARGIN_MEDIUM)
+ ->addMargin(PHUI::MARGIN_LARGE)
->appendChild($icon)
->appendChild($body);
@@ -256,8 +279,11 @@
$header = null;
break;
case self::HEADER_MODE_EDIT:
+ // In edit mode, include the panel monogram to make managing boards
+ // a little easier.
+ $header_text = pht('%s %s', $panel->getMonogram(), $panel->getName());
$header = id(new PHUIHeaderView())
- ->setHeader($panel->getName());
+ ->setHeader($header_text);
$header = $this->addPanelHeaderActions($header);
break;
case self::HEADER_MODE_NORMAL:
@@ -277,10 +303,13 @@
private function addPanelHeaderActions(
PHUIHeaderView $header) {
- $panel = $this->getPanel();
+ $viewer = $this->getViewer();
+ $panel = $this->getPanel();
$dashboard_id = $this->getDashboardID();
+ $actions = array();
+
if ($panel) {
$panel_id = $panel->getID();
@@ -290,12 +319,15 @@
$edit_uri->replaceQueryParam('dashboardID', $dashboard_id);
}
- $action_edit = id(new PHUIIconView())
+ $actions[] = id(new PhabricatorActionView())
->setIcon('fa-pencil')
- ->setWorkflow(true)
+ ->setName(pht('Edit Panel'))
->setHref((string)$edit_uri);
- $header->addActionItem($action_edit);
+ $actions[] = id(new PhabricatorActionView())
+ ->setIcon('fa-window-maximize')
+ ->setName(pht('View Panel Details'))
+ ->setHref($panel->getURI());
}
if ($dashboard_id) {
@@ -305,14 +337,28 @@
$remove_uri = id(new PhutilURI($remove_uri))
->replaceQueryParam('panelPHID', $panel_phid);
- $action_remove = id(new PHUIIconView())
- ->setIcon('fa-trash-o')
+ $actions[] = id(new PhabricatorActionView())
+ ->setIcon('fa-times')
->setHref((string)$remove_uri)
+ ->setName(pht('Remove Panel'))
->setWorkflow(true);
+ }
+
+ $dropdown_menu = id(new PhabricatorActionListView())
+ ->setViewer($viewer);
- $header->addActionItem($action_remove);
+ foreach ($actions as $action) {
+ $dropdown_menu->addAction($action);
}
+ $action_menu = id(new PHUIButtonView())
+ ->setTag('a')
+ ->setIcon('fa-cog')
+ ->setText(pht('Manage Panel'))
+ ->setDropdownMenu($dropdown_menu);
+
+ $header->addActionLink($action_menu);
+
return $header;
}
diff --git a/src/applications/dashboard/engine/PhabricatorDashboardPortalProfileMenuEngine.php b/src/applications/dashboard/engine/PhabricatorDashboardPortalProfileMenuEngine.php
--- a/src/applications/dashboard/engine/PhabricatorDashboardPortalProfileMenuEngine.php
+++ b/src/applications/dashboard/engine/PhabricatorDashboardPortalProfileMenuEngine.php
@@ -20,6 +20,8 @@
protected function getBuiltinProfileItems($object) {
$items = array();
+ $items[] = $this->newDividerItem('tail');
+
$items[] = $this->newManageItem();
$items[] = $this->newItem()
diff --git a/src/applications/dashboard/engine/PhabricatorDashboardRenderingEngine.php b/src/applications/dashboard/engine/PhabricatorDashboardRenderingEngine.php
--- a/src/applications/dashboard/engine/PhabricatorDashboardRenderingEngine.php
+++ b/src/applications/dashboard/engine/PhabricatorDashboardRenderingEngine.php
@@ -11,11 +11,19 @@
return $this;
}
+ public function getViewer() {
+ return $this->viewer;
+ }
+
public function setDashboard(PhabricatorDashboard $dashboard) {
$this->dashboard = $dashboard;
return $this;
}
+ public function getDashboard() {
+ return $this->dashboard;
+ }
+
public function setArrangeMode($mode) {
$this->arrangeMode = $mode;
return $this;
@@ -26,6 +34,8 @@
$dashboard = $this->dashboard;
$viewer = $this->viewer;
+ $is_editable = $this->arrangeMode;
+
$layout_config = $dashboard->getLayoutConfigObject();
$panel_grid_locations = $layout_config->getPanelLocations();
$panels = mpull($dashboard->getPanels(), null, 'getPHID');
@@ -35,12 +45,20 @@
->setFluidLayout(true)
->setGutter(AphrontMultiColumnView::GUTTER_LARGE);
- if ($this->arrangeMode) {
+ if ($is_editable) {
$h_mode = PhabricatorDashboardPanelRenderingEngine::HEADER_MODE_EDIT;
} else {
$h_mode = PhabricatorDashboardPanelRenderingEngine::HEADER_MODE_NORMAL;
}
+ $panel_phids = array();
+ foreach ($panel_grid_locations as $panel_column_locations) {
+ foreach ($panel_column_locations as $panel_phid) {
+ $panel_phids[] = $panel_phid;
+ }
+ }
+ $handles = $viewer->loadHandles($panel_phids);
+
foreach ($panel_grid_locations as $column => $panel_column_locations) {
$panel_phids = $panel_column_locations;
@@ -57,7 +75,8 @@
->setEnableAsyncRendering(true)
->setPanelPHID($panel_phid)
->setParentPanelPHIDs(array())
- ->setHeaderMode($h_mode);
+ ->setHeaderMode($h_mode)
+ ->setPanelHandle($handles[$panel_phid]);
$panel = idx($panels, $panel_phid);
if ($panel) {
@@ -68,8 +87,8 @@
}
$column_class = $layout_config->getColumnClass(
$column,
- $this->arrangeMode);
- if ($this->arrangeMode) {
+ $is_editable);
+ if ($is_editable) {
$column_result[] = $this->renderAddPanelPlaceHolder($column);
$column_result[] = $this->renderAddPanelUI($column);
}
@@ -80,7 +99,7 @@
$metadata = array('columnID' => $column));
}
- if ($this->arrangeMode) {
+ if ($is_editable) {
Javelin::initBehavior(
'dashboard-move-panels',
array(
@@ -91,7 +110,10 @@
$view = id(new PHUIBoxView())
->addClass('dashboard-view')
- ->appendChild($result);
+ ->appendChild(
+ array(
+ $result,
+ ));
return $view;
}
@@ -112,12 +134,12 @@
private function renderAddPanelUI($column) {
$dashboard_id = $this->dashboard->getID();
- $create_uri = id(new PhutilURI('/dashboard/panel/create/'))
+ $create_uri = id(new PhutilURI('/dashboard/panel/edit/'))
->replaceQueryParam('dashboardID', $dashboard_id)
- ->replaceQueryParam('column', $column);
+ ->replaceQueryParam('columnID', $column);
$add_uri = id(new PhutilURI('/dashboard/addpanel/'.$dashboard_id.'/'))
- ->replaceQueryParam('column', $column);
+ ->replaceQueryParam('columnID', $column);
$create_button = id(new PHUIButtonView())
->setTag('a')
diff --git a/src/applications/dashboard/install/PhabricatorDashboardApplicationInstallWorkflow.php b/src/applications/dashboard/install/PhabricatorDashboardApplicationInstallWorkflow.php
new file mode 100644
--- /dev/null
+++ b/src/applications/dashboard/install/PhabricatorDashboardApplicationInstallWorkflow.php
@@ -0,0 +1,58 @@
+<?php
+
+abstract class PhabricatorDashboardApplicationInstallWorkflow
+ extends PhabricatorDashboardInstallWorkflow {
+
+ abstract protected function newApplication();
+
+ protected function canInstallToGlobalMenu() {
+ return PhabricatorPolicyFilter::hasCapability(
+ $this->getViewer(),
+ $this->newApplication(),
+ PhabricatorPolicyCapability::CAN_EDIT);
+ }
+
+ public function handleRequest(AphrontRequest $request) {
+ $viewer = $this->getViewer();
+ $application = $this->newApplication();
+ $can_global = $this->canInstallToGlobalMenu();
+
+ switch ($this->getMode()) {
+ case 'global':
+ if (!$can_global) {
+ return $this->newGlobalPermissionDialog();
+ } else if ($request->isFormPost()) {
+ return $this->installDashboard($application, null);
+ } else {
+ return $this->newGlobalConfirmDialog();
+ }
+ case 'personal':
+ if ($request->isFormPost()) {
+ return $this->installDashboard($application, $viewer->getPHID());
+ } else {
+ return $this->newPersonalConfirmDialog();
+ }
+ }
+
+ $global_item = $this->newGlobalMenuItem()
+ ->setDisabled(!$can_global);
+
+ $menu = $this->newMenuFromItemMap(
+ array(
+ 'personal' => $this->newPersonalMenuItem(),
+ 'global' => $global_item,
+ ));
+
+ return $this->newApplicationModeDialog()
+ ->appendChild($menu);
+ }
+
+ abstract protected function newGlobalPermissionDialog();
+ abstract protected function newGlobalConfirmDialog();
+ abstract protected function newPersonalConfirmDialog();
+
+ abstract protected function newPersonalMenuItem();
+ abstract protected function newGlobalMenuItem();
+ abstract protected function newApplicationModeDialog();
+
+}
diff --git a/src/applications/dashboard/install/PhabricatorDashboardFavoritesInstallWorkflow.php b/src/applications/dashboard/install/PhabricatorDashboardFavoritesInstallWorkflow.php
new file mode 100644
--- /dev/null
+++ b/src/applications/dashboard/install/PhabricatorDashboardFavoritesInstallWorkflow.php
@@ -0,0 +1,85 @@
+<?php
+
+final class PhabricatorDashboardFavoritesInstallWorkflow
+ extends PhabricatorDashboardApplicationInstallWorkflow {
+
+ const WORKFLOWKEY = 'favorites';
+
+ public function getOrder() {
+ return 4000;
+ }
+
+ protected function newWorkflowMenuItem() {
+ return $this->newMenuItem()
+ ->setHeader(pht('Add to Favorites Menu'))
+ ->setImageIcon('fa-bookmark')
+ ->addAttribute(
+ pht(
+ 'Add this dashboard to the favorites menu in the main '.
+ 'menu bar.'));
+ }
+
+ protected function newProfileEngine() {
+ return new PhabricatorFavoritesProfileMenuEngine();
+ }
+
+ protected function newApplication() {
+ return new PhabricatorFavoritesApplication();
+ }
+
+ protected function newApplicationModeDialog() {
+ return $this->newDialog()
+ ->setTitle(pht('Add Dashboard to Favorites Menu'));
+ }
+
+ protected function newPersonalMenuItem() {
+ return $this->newMenuItem()
+ ->setHeader(pht('Add to Personal Favorites'))
+ ->setImageIcon('fa-user')
+ ->addAttribute(
+ pht(
+ 'Add this dashboard to your list of personal favorite menu items, '.
+ 'visible to only you.'));
+ }
+
+ protected function newGlobalMenuItem() {
+ return $this->newMenuItem()
+ ->setHeader(pht('Add to Global Favorites'))
+ ->setImageIcon('fa-globe')
+ ->addAttribute(
+ pht(
+ 'Add this dashboard to the global favorites menu, visible to all '.
+ 'users.'));
+ }
+
+ protected function newGlobalPermissionDialog() {
+ return $this->newDialog()
+ ->setTitle(pht('No Permission'))
+ ->appendParagraph(
+ pht(
+ 'You do not have permission to install items on the global '.
+ 'favorites menu.'));
+ }
+
+ protected function newGlobalConfirmDialog() {
+ return $this->newDialog()
+ ->setTitle(pht('Add Dashboard to Global Favorites'))
+ ->appendParagraph(
+ pht(
+ 'Add dashboard %s as a global menu item in the favorites menu?',
+ $this->getDashboardDisplayName()))
+ ->addSubmitButton(pht('Add to Favorites'));
+ }
+
+ protected function newPersonalConfirmDialog() {
+ return $this->newDialog()
+ ->setTitle(pht('Add Dashboard to Personal Favorites'))
+ ->appendParagraph(
+ pht(
+ 'Add dashboard %s as a personal menu item in the favorites menu?',
+ $this->getDashboardDisplayName()))
+ ->addSubmitButton(pht('Add to Favorites'));
+ }
+
+
+}
diff --git a/src/applications/dashboard/install/PhabricatorDashboardHomeInstallWorkflow.php b/src/applications/dashboard/install/PhabricatorDashboardHomeInstallWorkflow.php
new file mode 100644
--- /dev/null
+++ b/src/applications/dashboard/install/PhabricatorDashboardHomeInstallWorkflow.php
@@ -0,0 +1,83 @@
+<?php
+
+final class PhabricatorDashboardHomeInstallWorkflow
+ extends PhabricatorDashboardApplicationInstallWorkflow {
+
+ const WORKFLOWKEY = 'home';
+
+ public function getOrder() {
+ return 1000;
+ }
+
+ protected function newWorkflowMenuItem() {
+ return $this->newMenuItem()
+ ->setHeader(pht('Add to Home Page Menu'))
+ ->setImageIcon('fa-home')
+ ->addAttribute(
+ pht(
+ 'Add this dashboard to the menu on the home page.'));
+ }
+
+ protected function newProfileEngine() {
+ return new PhabricatorHomeProfileMenuEngine();
+ }
+
+ protected function newApplication() {
+ return new PhabricatorHomeApplication();
+ }
+
+ protected function newApplicationModeDialog() {
+ return $this->newDialog()
+ ->setTitle(pht('Add Dashboard to Home Menu'));
+ }
+
+ protected function newPersonalMenuItem() {
+ return $this->newMenuItem()
+ ->setHeader(pht('Add to Personal Home Menu'))
+ ->setImageIcon('fa-user')
+ ->addAttribute(
+ pht(
+ 'Add this dashboard to your list of personal home menu items, '.
+ 'visible to only you.'));
+ }
+
+ protected function newGlobalMenuItem() {
+ return $this->newMenuItem()
+ ->setHeader(pht('Add to Global Home Menu'))
+ ->setImageIcon('fa-globe')
+ ->addAttribute(
+ pht(
+ 'Add this dashboard to the global home menu, visible to all '.
+ 'users.'));
+ }
+
+ protected function newGlobalPermissionDialog() {
+ return $this->newDialog()
+ ->setTitle(pht('No Permission'))
+ ->appendParagraph(
+ pht(
+ 'You do not have permission to install items on the global home '.
+ 'menu.'));
+ }
+
+ protected function newGlobalConfirmDialog() {
+ return $this->newDialog()
+ ->setTitle(pht('Add Dashboard to Global Home Page'))
+ ->appendParagraph(
+ pht(
+ 'Add dashboard %s as a global menu item on the home page?',
+ $this->getDashboardDisplayName()))
+ ->addSubmitButton(pht('Add to Home'));
+ }
+
+ protected function newPersonalConfirmDialog() {
+ return $this->newDialog()
+ ->setTitle(pht('Add Dashboard to Personal Home Page'))
+ ->appendParagraph(
+ pht(
+ 'Add dashboard %s as a personal menu item on your home page?',
+ $this->getDashboardDisplayName()))
+ ->addSubmitButton(pht('Add to Home'));
+ }
+
+}
diff --git a/src/applications/dashboard/install/PhabricatorDashboardInstallWorkflow.php b/src/applications/dashboard/install/PhabricatorDashboardInstallWorkflow.php
new file mode 100644
--- /dev/null
+++ b/src/applications/dashboard/install/PhabricatorDashboardInstallWorkflow.php
@@ -0,0 +1,143 @@
+<?php
+
+abstract class PhabricatorDashboardInstallWorkflow
+ extends Phobject {
+
+ private $request;
+ private $viewer;
+ private $dashboard;
+ private $mode;
+
+ final public function setViewer(PhabricatorUser $viewer) {
+ $this->viewer = $viewer;
+ return $this;
+ }
+
+ final public function getViewer() {
+ return $this->viewer;
+ }
+
+ final public function setDashboard(PhabricatorDashboard $dashboard) {
+ $this->dashboard = $dashboard;
+ return $this;
+ }
+
+ final public function getDashboard() {
+ return $this->dashboard;
+ }
+
+ final public function setMode($mode) {
+ $this->mode = $mode;
+ return $this;
+ }
+
+ final public function getMode() {
+ return $this->mode;
+ }
+
+ final public function setRequest(AphrontRequest $request) {
+ $this->request = $request;
+ return $this;
+ }
+
+ final public function getRequest() {
+ return $this->request;
+ }
+
+ final public function getWorkflowKey() {
+ return $this->getPhobjectClassConstant('WORKFLOWKEY', 32);
+ }
+
+ final public static function getAllWorkflows() {
+ return id(new PhutilClassMapQuery())
+ ->setAncestorClass(__CLASS__)
+ ->setUniqueMethod('getWorkflowKey')
+ ->setSortMethod('getOrder')
+ ->execute();
+ }
+
+ final public function getWorkflowMenuItem() {
+ return $this->newWorkflowMenuItem();
+ }
+
+ abstract public function getOrder();
+ abstract protected function newWorkflowMenuItem();
+
+ final protected function newMenuItem() {
+ return id(new PHUIObjectItemView())
+ ->setClickable(true);
+ }
+
+ abstract public function handleRequest(AphrontRequest $request);
+
+ final protected function newDialog() {
+ $dashboard = $this->getDashboard();
+
+ return id(new AphrontDialogView())
+ ->setViewer($this->getViewer())
+ ->setWidth(AphrontDialogView::WIDTH_FORM)
+ ->addCancelButton($dashboard->getURI());
+ }
+
+ final protected function newMenuFromItemMap(array $map) {
+ $viewer = $this->getViewer();
+ $dashboard = $this->getDashboard();
+
+ $menu = id(new PHUIObjectItemListView())
+ ->setViewer($viewer)
+ ->setFlush(true)
+ ->setBig(true);
+
+ foreach ($map as $key => $item) {
+ $item->setHref(
+ urisprintf(
+ '/dashboard/install/%d/%s/%s/',
+ $dashboard->getID(),
+ $this->getWorkflowKey(),
+ $key));
+
+ $menu->addItem($item);
+ }
+
+ return $menu;
+ }
+
+ abstract protected function newProfileEngine();
+
+ final protected function installDashboard($profile_object, $custom_phid) {
+ $dashboard = $this->getDashboard();
+ $engine = $this->newProfileEngine()
+ ->setProfileObject($profile_object);
+
+ $request = $this->getRequest();
+ $viewer = $this->getViewer();
+
+ $config = PhabricatorProfileMenuItemConfiguration::initializeNewItem(
+ $profile_object,
+ new PhabricatorDashboardProfileMenuItem(),
+ $custom_phid);
+
+ $config->setMenuItemProperty('dashboardPHID', $dashboard->getPHID());
+
+ $xactions = array();
+
+ $editor = id(new PhabricatorProfileMenuEditor())
+ ->setActor($viewer)
+ ->setContinueOnNoEffect(true)
+ ->setContinueOnMissingFields(true)
+ ->setContentSourceFromRequest($request);
+
+ $editor->applyTransactions($config, $xactions);
+
+ $done_uri = $engine->getItemURI(urisprintf('view/%d/', $config->getID()));
+
+ return id(new AphrontRedirectResponse())
+ ->setURI($done_uri);
+ }
+
+ final protected function getDashboardDisplayName() {
+ $dashboard = $this->getDashboard();
+ return phutil_tag('strong', array(), $dashboard->getName());
+ }
+
+}
diff --git a/src/applications/dashboard/install/PhabricatorDashboardObjectInstallWorkflow.php b/src/applications/dashboard/install/PhabricatorDashboardObjectInstallWorkflow.php
new file mode 100644
--- /dev/null
+++ b/src/applications/dashboard/install/PhabricatorDashboardObjectInstallWorkflow.php
@@ -0,0 +1,99 @@
+<?php
+
+abstract class PhabricatorDashboardObjectInstallWorkflow
+ extends PhabricatorDashboardInstallWorkflow {
+
+ abstract protected function newQuery();
+ abstract protected function newConfirmDialog($object);
+ abstract protected function newObjectSelectionForm($object);
+
+ public function handleRequest(AphrontRequest $request) {
+ $viewer = $this->getViewer();
+
+ $target_identifier = null;
+
+ $target_tokens = $request->getArr('target');
+ if ($target_tokens) {
+ $target_identifier = head($target_tokens);
+ }
+
+ if (!strlen($target_identifier)) {
+ $target_identifier = $request->getStr('target');
+ }
+
+ if (!strlen($target_identifier)) {
+ $target_identifier = $this->getMode();
+ }
+
+ $target = null;
+ if (strlen($target_identifier)) {
+ $targets = array();
+
+ if (ctype_digit($target_identifier)) {
+ $targets = $this->newQuery()
+ ->setViewer($viewer)
+ ->withIDs(array((int)$target_identifier))
+ ->execute();
+ }
+
+ if (!$targets) {
+ $targets = $this->newQuery()
+ ->setViewer($viewer)
+ ->withPHIDs(array($target_identifier))
+ ->execute();
+ }
+
+ if ($targets) {
+ $target = head($targets);
+ }
+ }
+
+ if ($target) {
+ $target_phid = $target->getPHID();
+ } else {
+ $target_phid = null;
+ }
+
+ if ($target) {
+ $can_edit = PhabricatorPolicyFilter::hasCapability(
+ $viewer,
+ $target,
+ PhabricatorPolicyCapability::CAN_EDIT);
+ } else {
+ $can_edit = null;
+ }
+
+ if ($request->isFormPost() && $target && $can_edit) {
+ if ($request->getBool('confirm')) {
+ return $this->installDashboard($target, null);
+ } else {
+ return $this->newConfirmDialog($target)
+ ->addHiddenInput('confirm', 1)
+ ->addHiddenInput('target', $target_phid);
+ }
+ }
+
+ $errors = array();
+ if (strlen($target_identifier)) {
+ if (!$target) {
+ $errors[] = pht('Choose a valid object.');
+ } else if (!$can_edit) {
+ $errors[] = pht(
+ 'You do not have permission to edit the selected object. '.
+ 'You can only install dashboards on objects you can edit.');
+ }
+ } else if ($request->getBool('pick')) {
+ $errors[] = pht(
+ 'Choose an object to install this dashboard on.');
+ }
+
+ $form = $this->newObjectSelectionForm($target)
+ ->addHiddenInput('pick', 1);
+
+ return $this->newDialog()
+ ->setTitle(pht('Add Dashboard to Project Menu'))
+ ->setErrors($errors)
+ ->appendForm($form)
+ ->addSubmitButton(pht('Continue'));
+ }
+}
diff --git a/src/applications/dashboard/install/PhabricatorDashboardPortalInstallWorkflow.php b/src/applications/dashboard/install/PhabricatorDashboardPortalInstallWorkflow.php
new file mode 100644
--- /dev/null
+++ b/src/applications/dashboard/install/PhabricatorDashboardPortalInstallWorkflow.php
@@ -0,0 +1,62 @@
+<?php
+
+final class PhabricatorDashboardPortalInstallWorkflow
+ extends PhabricatorDashboardObjectInstallWorkflow {
+
+ const WORKFLOWKEY = 'portal';
+
+ public function getOrder() {
+ return 2000;
+ }
+
+ protected function newWorkflowMenuItem() {
+ return $this->newMenuItem()
+ ->setHeader(pht('Add to Portal Menu'))
+ ->setImageIcon('fa-compass')
+ ->addAttribute(
+ pht('Add this dashboard to the menu on a portal.'));
+ }
+
+ protected function newProfileEngine() {
+ return new PhabricatorDashboardPortalProfileMenuEngine();
+ }
+
+ protected function newQuery() {
+ return new PhabricatorDashboardPortalQuery();
+ }
+
+ protected function newConfirmDialog($object) {
+ return $this->newDialog()
+ ->setTitle(pht('Add Dashboard to Portal Menu'))
+ ->appendParagraph(
+ pht(
+ 'Add the dashboard %s to portal %s?',
+ $this->getDashboardDisplayName(),
+ phutil_tag('strong', array(), $object->getName())))
+ ->addSubmitButton(pht('Add to Portal'));
+ }
+ protected function newObjectSelectionForm($object) {
+ $viewer = $this->getViewer();
+
+ if ($object) {
+ $tokenizer_value = array($object->getPHID());
+ } else {
+ $tokenizer_value = array();
+ }
+
+ return id(new AphrontFormView())
+ ->setViewer($viewer)
+ ->appendInstructions(
+ pht(
+ 'Select which portal you want to add the dashboard %s to.',
+ $this->getDashboardDisplayName()))
+ ->appendControl(
+ id(new AphrontFormTokenizerControl())
+ ->setName('target')
+ ->setLimit(1)
+ ->setLabel(pht('Add to Portal'))
+ ->setValue($tokenizer_value)
+ ->setDatasource(new PhabricatorDashboardPortalDatasource()));
+ }
+
+}
diff --git a/src/applications/dashboard/install/PhabricatorDashboardProjectInstallWorkflow.php b/src/applications/dashboard/install/PhabricatorDashboardProjectInstallWorkflow.php
new file mode 100644
--- /dev/null
+++ b/src/applications/dashboard/install/PhabricatorDashboardProjectInstallWorkflow.php
@@ -0,0 +1,63 @@
+<?php
+
+final class PhabricatorDashboardProjectInstallWorkflow
+ extends PhabricatorDashboardObjectInstallWorkflow {
+
+ const WORKFLOWKEY = 'project';
+
+ public function getOrder() {
+ return 3000;
+ }
+
+ protected function newWorkflowMenuItem() {
+ return $this->newMenuItem()
+ ->setHeader(pht('Add to Project Menu'))
+ ->setImageIcon('fa-briefcase')
+ ->addAttribute(
+ pht('Add this dashboard to the menu for a project.'));
+ }
+
+ protected function newProfileEngine() {
+ return new PhabricatorProjectProfileMenuEngine();
+ }
+
+ protected function newQuery() {
+ return new PhabricatorProjectQuery();
+ }
+
+ protected function newConfirmDialog($object) {
+ return $this->newDialog()
+ ->setTitle(pht('Add Dashboard to Project Menu'))
+ ->appendParagraph(
+ pht(
+ 'Add the dashboard %s to the menu for project %s?',
+ $this->getDashboardDisplayName(),
+ phutil_tag('strong', array(), $object->getName())))
+ ->addSubmitButton(pht('Add to Project'));
+ }
+
+ protected function newObjectSelectionForm($object) {
+ $viewer = $this->getViewer();
+
+ if ($object) {
+ $tokenizer_value = array($object->getPHID());
+ } else {
+ $tokenizer_value = array();
+ }
+
+ return id(new AphrontFormView())
+ ->setViewer($viewer)
+ ->appendInstructions(
+ pht(
+ 'Select which project menu you want to add the dashboard %s to.',
+ $this->getDashboardDisplayName()))
+ ->appendControl(
+ id(new AphrontFormTokenizerControl())
+ ->setName('target')
+ ->setLimit(1)
+ ->setLabel(pht('Add to Project'))
+ ->setValue($tokenizer_value)
+ ->setDatasource(new PhabricatorProjectDatasource()));
+ }
+
+}
diff --git a/src/applications/dashboard/paneltype/PhabricatorDashboardPanelType.php b/src/applications/dashboard/paneltype/PhabricatorDashboardPanelType.php
--- a/src/applications/dashboard/paneltype/PhabricatorDashboardPanelType.php
+++ b/src/applications/dashboard/paneltype/PhabricatorDashboardPanelType.php
@@ -5,7 +5,6 @@
abstract public function getPanelTypeKey();
abstract public function getPanelTypeName();
abstract public function getPanelTypeDescription();
- abstract public function getFieldSpecifications();
abstract public function getIcon();
abstract public function renderPanelContent(
@@ -53,4 +52,11 @@
->execute();
}
+ final public function getEditEngineFields(PhabricatorDashboardPanel $panel) {
+ return $this->newEditEngineFields($panel);
+ }
+
+ abstract protected function newEditEngineFields(
+ PhabricatorDashboardPanel $panel);
+
}
diff --git a/src/applications/dashboard/paneltype/PhabricatorDashboardQueryPanelType.php b/src/applications/dashboard/paneltype/PhabricatorDashboardQueryPanelType.php
--- a/src/applications/dashboard/paneltype/PhabricatorDashboardQueryPanelType.php
+++ b/src/applications/dashboard/paneltype/PhabricatorDashboardQueryPanelType.php
@@ -21,22 +21,29 @@
'revisions you need to review.');
}
- public function getFieldSpecifications() {
+ protected function newEditEngineFields(PhabricatorDashboardPanel $panel) {
+ $application_field =
+ id(new PhabricatorDashboardQueryPanelApplicationEditField())
+ ->setKey('class')
+ ->setLabel(pht('Search For'))
+ ->setTransactionType(
+ PhabricatorDashboardQueryPanelApplicationTransaction::TRANSACTIONTYPE)
+ ->setValue($panel->getProperty('class', ''));
+
+ $application_id = $application_field->getControlID();
+
+ $query_field =
+ id(new PhabricatorDashboardQueryPanelQueryEditField())
+ ->setKey('key')
+ ->setLabel(pht('Query'))
+ ->setApplicationControlID($application_id)
+ ->setTransactionType(
+ PhabricatorDashboardQueryPanelQueryTransaction::TRANSACTIONTYPE)
+ ->setValue($panel->getProperty('key', ''));
+
return array(
- 'class' => array(
- 'name' => pht('Search For'),
- 'type' => 'search.application',
- ),
- 'key' => array(
- 'name' => pht('Query'),
- 'type' => 'search.query',
- 'control.application' => 'class',
- ),
- 'limit' => array(
- 'name' => pht('Limit'),
- 'caption' => pht('Leave this blank for the default number of items.'),
- 'type' => 'text',
- ),
+ $application_field,
+ $query_field,
);
}
diff --git a/src/applications/dashboard/paneltype/PhabricatorDashboardTabsPanelType.php b/src/applications/dashboard/paneltype/PhabricatorDashboardTabsPanelType.php
--- a/src/applications/dashboard/paneltype/PhabricatorDashboardTabsPanelType.php
+++ b/src/applications/dashboard/paneltype/PhabricatorDashboardTabsPanelType.php
@@ -12,20 +12,15 @@
}
public function getIcon() {
- return 'fa-window-maximize';
+ return 'fa-columns';
}
public function getPanelTypeDescription() {
return pht('Use tabs to switch between several other panels.');
}
- public function getFieldSpecifications() {
- return array(
- 'config' => array(
- 'name' => pht('Tabs'),
- 'type' => 'dashboard.tabs',
- ),
- );
+ protected function newEditEngineFields(PhabricatorDashboardPanel $panel) {
+ return array();
}
public function shouldRenderAsync() {
@@ -33,37 +28,37 @@
return false;
}
+ public function getPanelConfiguration(PhabricatorDashboardPanel $panel) {
+ $config = $panel->getProperty('config');
+
+ if (!is_array($config)) {
+ // NOTE: The older version of this panel stored raw JSON.
+ try {
+ $config = phutil_json_decode($config);
+ } catch (PhutilJSONParserException $ex) {
+ $config = array();
+ }
+ }
+
+ return $config;
+ }
+
public function renderPanelContent(
PhabricatorUser $viewer,
PhabricatorDashboardPanel $panel,
PhabricatorDashboardPanelRenderingEngine $engine) {
- $config = $panel->getProperty('config');
- if (!is_array($config)) {
- // NOTE: The older version of this panel stored raw JSON.
- $config = phutil_json_decode($config);
- }
+ $is_edit = $engine->isEditMode();
+ $config = $this->getPanelConfiguration($panel);
$list = id(new PHUIListView())
->setType(PHUIListView::NAVBAR_LIST);
- $selected = 0;
-
$node_ids = array();
foreach ($config as $idx => $tab_spec) {
$node_ids[$idx] = celerity_generate_unique_node_id();
}
- foreach ($config as $idx => $tab_spec) {
- $list->addMenuItem(
- id(new PHUIListItemView())
- ->setHref('#')
- ->setSelected($idx == $selected)
- ->addSigil('dashboard-tab-panel-tab')
- ->setMetadata(array('idx' => $idx))
- ->setName(idx($tab_spec, 'name', pht('Nameless Tab'))));
- }
-
$ids = ipull($config, 'panelID');
if ($ids) {
$panels = id(new PhabricatorDashboardPanelQuery())
@@ -74,6 +69,135 @@
$panels = array();
}
+ $id = $panel->getID();
+
+ $add_uri = urisprintf('/dashboard/panel/tabs/%d/add/', $id);
+ $add_uri = new PhutilURI($add_uri);
+
+ $remove_uri = urisprintf('/dashboard/panel/tabs/%d/remove/', $id);
+ $remove_uri = new PhutilURI($remove_uri);
+
+ $rename_uri = urisprintf('/dashboard/panel/tabs/%d/rename/', $id);
+ $rename_uri = new PhutilURI($rename_uri);
+
+ $selected = 0;
+
+ $last_idx = null;
+ foreach ($config as $idx => $tab_spec) {
+ $panel_id = idx($tab_spec, 'panelID');
+ $subpanel = idx($panels, $panel_id);
+
+ $name = idx($tab_spec, 'name');
+ if (!strlen($name)) {
+ if ($subpanel) {
+ $name = $subpanel->getName();
+ }
+ }
+
+ if (!strlen($name)) {
+ $name = pht('Unnamed Tab');
+ }
+
+ $tab_view = id(new PHUIListItemView())
+ ->setHref('#')
+ ->setSelected($idx == $selected)
+ ->addSigil('dashboard-tab-panel-tab')
+ ->setMetadata(array('idx' => $idx))
+ ->setName($name);
+
+ if ($is_edit) {
+ $dropdown_menu = id(new PhabricatorActionListView())
+ ->setViewer($viewer);
+
+ $remove_tab_uri = id(clone $remove_uri)
+ ->replaceQueryParam('target', $idx);
+
+ $rename_tab_uri = id(clone $rename_uri)
+ ->replaceQueryParam('target', $idx);
+
+ if ($subpanel) {
+ $details_uri = $subpanel->getURI();
+ } else {
+ $details_uri = null;
+ }
+
+ $edit_uri = urisprintf(
+ '/dashboard/panel/edit/%d/',
+ $panel_id);
+ if ($subpanel) {
+ $can_edit = PhabricatorPolicyFilter::hasCapability(
+ $viewer,
+ $subpanel,
+ PhabricatorPolicyCapability::CAN_EDIT);
+ } else {
+ $can_edit = false;
+ }
+
+ $dropdown_menu->addAction(
+ id(new PhabricatorActionView())
+ ->setName(pht('Rename Tab'))
+ ->setIcon('fa-pencil')
+ ->setHref($rename_tab_uri)
+ ->setWorkflow(true));
+
+ $dropdown_menu->addAction(
+ id(new PhabricatorActionView())
+ ->setName(pht('Remove Tab'))
+ ->setIcon('fa-times')
+ ->setHref($remove_tab_uri)
+ ->setWorkflow(true));
+
+ $dropdown_menu->addAction(
+ id(new PhabricatorActionView())
+ ->setType(PhabricatorActionView::TYPE_DIVIDER));
+
+ $dropdown_menu->addAction(
+ id(new PhabricatorActionView())
+ ->setName(pht('Edit Panel'))
+ ->setIcon('fa-pencil')
+ ->setHref($edit_uri)
+ ->setWorkflow(true)
+ ->setDisabled(!$can_edit));
+
+ $dropdown_menu->addAction(
+ id(new PhabricatorActionView())
+ ->setName(pht('View Panel Details'))
+ ->setIcon('fa-window-maximize')
+ ->setHref($details_uri)
+ ->setDisabled(!$subpanel));
+
+ $tab_view->setDropdownMenu($dropdown_menu);
+ }
+
+ $list->addMenuItem($tab_view);
+
+ $last_idx = $idx;
+ }
+
+ if ($is_edit) {
+ $actions = id(new PhabricatorActionListView())
+ ->setViewer($viewer);
+
+ $add_last_uri = clone $add_uri;
+ if ($last_idx) {
+ $add_last_uri->replaceQueryParam('after', $last_idx);
+ }
+
+ $actions->addAction(
+ id(new PhabricatorActionView())
+ ->setName(pht('Add Existing Panel'))
+ ->setIcon('fa-window-maximize')
+ ->setHref($add_last_uri)
+ ->setWorkflow(true));
+
+ $list->addMenuItem(
+ id(new PHUIListItemView())
+ ->setHref('#')
+ ->setSelected(false)
+ ->setName(pht('Add Tab...'))
+ ->setDropdownMenu($actions));
+ }
+
$parent_phids = $engine->getParentPanelPHIDs();
$parent_phids[] = $panel->getPHID();
@@ -87,15 +211,15 @@
$no_headers = PhabricatorDashboardPanelRenderingEngine::HEADER_MODE_NONE;
foreach ($config as $idx => $tab_spec) {
$panel_id = idx($tab_spec, 'panelID');
- $panel = idx($panels, $panel_id);
+ $subpanel = idx($panels, $panel_id);
- if ($panel) {
+ if ($subpanel) {
$panel_content = id(new PhabricatorDashboardPanelRenderingEngine())
->setViewer($viewer)
->setEnableAsyncRendering(true)
->setParentPanelPHIDs($parent_phids)
- ->setPanel($panel)
- ->setPanelPHID($panel->getPHID())
+ ->setPanel($subpanel)
+ ->setPanelPHID($subpanel->getPHID())
->setHeaderMode($no_headers)
->setMovable(false)
->renderPanel();
@@ -112,6 +236,28 @@
$panel_content);
}
+ if (!$content) {
+ if ($is_edit) {
+ $message = pht(
+ 'This tab panel does not have any tabs yet. Use "Add Tab" to '.
+ 'create or place a tab.');
+ } else {
+ $message = pht(
+ 'This tab panel does not have any tabs yet.');
+ }
+
+ $content = id(new PHUIInfoView())
+ ->setSeverity(PHUIInfoView::SEVERITY_NODATA)
+ ->setErrors(
+ array(
+ $message,
+ ));
+
+ $content = id(new PHUIBoxView())
+ ->addClass('mlt mlb')
+ ->appendChild($content);
+ }
+
Javelin::initBehavior('dashboard-tab-panel');
return javelin_tag(
diff --git a/src/applications/dashboard/paneltype/PhabricatorDashboardTextPanelType.php b/src/applications/dashboard/paneltype/PhabricatorDashboardTextPanelType.php
--- a/src/applications/dashboard/paneltype/PhabricatorDashboardTextPanelType.php
+++ b/src/applications/dashboard/paneltype/PhabricatorDashboardTextPanelType.php
@@ -12,21 +12,23 @@
}
public function getIcon() {
- return 'fa-paragraph';
+ return 'fa-file-text-o';
}
public function getPanelTypeDescription() {
return pht(
- 'Add some static text to the dashboard. This can be used to '.
- 'provide instructions or context.');
+ 'Add a text panel to the dashboard to provide instructions or '.
+ 'context.');
}
- public function getFieldSpecifications() {
+ protected function newEditEngineFields(PhabricatorDashboardPanel $panel) {
return array(
- 'text' => array(
- 'name' => pht('Text'),
- 'type' => 'remarkup',
- ),
+ id(new PhabricatorRemarkupEditField())
+ ->setKey('text')
+ ->setLabel(pht('Text'))
+ ->setTransactionType(
+ PhabricatorDashboardTextPanelTextTransaction::TRANSACTIONTYPE)
+ ->setValue($panel->getProperty('text', '')),
);
}
diff --git a/src/applications/dashboard/query/PhabricatorDashboardSearchEngine.php b/src/applications/dashboard/query/PhabricatorDashboardSearchEngine.php
--- a/src/applications/dashboard/query/PhabricatorDashboardSearchEngine.php
+++ b/src/applications/dashboard/query/PhabricatorDashboardSearchEngine.php
@@ -123,15 +123,14 @@
$handles = $viewer->loadHandles($phids);
$list = id(new PHUIObjectItemListView())
- ->setUser($viewer);
+ ->setViewer($viewer);
foreach ($dashboards as $dashboard) {
- $id = $dashboard->getID();
-
$item = id(new PHUIObjectItemView())
- ->setUser($viewer)
+ ->setViewer($viewer)
+ ->setObjectName($dashboard->getObjectName())
->setHeader($dashboard->getName())
- ->setHref($this->getApplicationURI("view/{$id}/"))
+ ->setHref($dashboard->getURI())
->setObject($dashboard);
$bg_color = 'bg-dark';
diff --git a/src/applications/dashboard/storage/PhabricatorDashboard.php b/src/applications/dashboard/storage/PhabricatorDashboard.php
--- a/src/applications/dashboard/storage/PhabricatorDashboard.php
+++ b/src/applications/dashboard/storage/PhabricatorDashboard.php
@@ -118,10 +118,13 @@
return ($this->getStatus() == self::STATUS_ARCHIVED);
}
- public function getViewURI() {
- return '/dashboard/view/'.$this->getID().'/';
+ public function getURI() {
+ return urisprintf('/dashboard/view/%d/', $this->getID());
}
+ public function getObjectName() {
+ return pht('Dashboard %d', $this->getID());
+ }
/* -( PhabricatorApplicationTransactionInterface )------------------------- */
diff --git a/src/applications/dashboard/storage/PhabricatorDashboardPanel.php b/src/applications/dashboard/storage/PhabricatorDashboardPanel.php
--- a/src/applications/dashboard/storage/PhabricatorDashboardPanel.php
+++ b/src/applications/dashboard/storage/PhabricatorDashboardPanel.php
@@ -8,7 +8,6 @@
implements
PhabricatorApplicationTransactionInterface,
PhabricatorPolicyInterface,
- PhabricatorCustomFieldInterface,
PhabricatorFlaggableInterface,
PhabricatorDestructibleInterface,
PhabricatorNgramsInterface {
@@ -21,8 +20,6 @@
protected $isArchived = 0;
protected $properties = array();
- private $customFields = self::ATTACHABLE;
-
public static function initializeNewPanel(PhabricatorUser $actor) {
return id(new PhabricatorDashboardPanel())
->setName('')
@@ -105,6 +102,10 @@
return $impl;
}
+ public function getEditEngineFields() {
+ return $this->requireImplementation()->getEditEngineFields($this);
+ }
+
/* -( PhabricatorApplicationTransactionInterface )------------------------- */
@@ -142,27 +143,6 @@
}
-/* -( PhabricatorCustomFieldInterface )------------------------------------ */
-
-
- public function getCustomFieldSpecificationForRole($role) {
- return array();
- }
-
- public function getCustomFieldBaseClass() {
- return 'PhabricatorDashboardPanelCustomField';
- }
-
- public function getCustomFields() {
- return $this->assertAttached($this->customFields);
- }
-
- public function attachCustomFields(PhabricatorCustomFieldAttachment $fields) {
- $this->customFields = $fields;
- return $this;
- }
-
-
/* -( PhabricatorDestructibleInterface )----------------------------------- */
diff --git a/src/applications/dashboard/storage/PhabricatorDashboardPanelTransaction.php b/src/applications/dashboard/storage/PhabricatorDashboardPanelTransaction.php
--- a/src/applications/dashboard/storage/PhabricatorDashboardPanelTransaction.php
+++ b/src/applications/dashboard/storage/PhabricatorDashboardPanelTransaction.php
@@ -1,10 +1,7 @@
<?php
final class PhabricatorDashboardPanelTransaction
- extends PhabricatorApplicationTransaction {
-
- const TYPE_NAME = 'dashpanel:name';
- const TYPE_ARCHIVE = 'dashboard:archive';
+ extends PhabricatorModularTransaction {
public function getApplicationName() {
return 'dashboard';
@@ -14,99 +11,8 @@
return PhabricatorDashboardPanelPHIDType::TYPECONST;
}
- public function getTitle() {
- $author_phid = $this->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);
- }
- case self::TYPE_ARCHIVE:
- if ($new) {
- return pht(
- '%s archived this panel.',
- $author_link);
- } else {
- return pht(
- '%s activated this panel.',
- $author_link);
- }
- }
-
- return parent::getTitle();
- }
-
- public function getTitleForFeed() {
- $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);
- }
- case self::TYPE_ARCHIVE:
- if ($new) {
- return pht(
- '%s archived dashboard panel %s.',
- $author_link,
- $object_link);
- } else {
- return pht(
- '%s activated dashboard panel %s.',
- $author_link,
- $object_link);
- }
- }
-
- return parent::getTitleForFeed();
+ public function getBaseTransactionClass() {
+ return 'PhabricatorDashboardPanelTransactionType';
}
- 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/typeahead/PhabricatorDashboardPanelDatasource.php b/src/applications/dashboard/typeahead/PhabricatorDashboardPanelDatasource.php
--- a/src/applications/dashboard/typeahead/PhabricatorDashboardPanelDatasource.php
+++ b/src/applications/dashboard/typeahead/PhabricatorDashboardPanelDatasource.php
@@ -48,13 +48,13 @@
$type_text = nonempty($panel->getPanelType(), pht('Unknown Type'));
$icon = 'fa-question';
}
- $id = $panel->getID();
+ $phid = $panel->getPHID();
$monogram = $panel->getMonogram();
$properties = $panel->getProperties();
$result = id(new PhabricatorTypeaheadResult())
->setName($monogram.' '.$panel->getName())
- ->setPHID($id)
+ ->setPHID($phid)
->setIcon($icon)
->addAttribute($type_text);
@@ -66,7 +66,7 @@
$result->setClosed(pht('Archived'));
}
- $results[$id] = $result;
+ $results[$phid] = $result;
}
return $results;
diff --git a/src/applications/dashboard/typeahead/PhabricatorDashboardPortalDatasource.php b/src/applications/dashboard/typeahead/PhabricatorDashboardPortalDatasource.php
new file mode 100644
--- /dev/null
+++ b/src/applications/dashboard/typeahead/PhabricatorDashboardPortalDatasource.php
@@ -0,0 +1,47 @@
+<?php
+
+final class PhabricatorDashboardPortalDatasource
+ extends PhabricatorTypeaheadDatasource {
+
+ public function getBrowseTitle() {
+ return pht('Browse Portals');
+ }
+
+ public function getPlaceholderText() {
+ return pht('Type a portal name...');
+ }
+
+ public function getDatasourceApplicationClass() {
+ return 'PhabricatorDashboardApplication';
+ }
+
+ public function loadResults() {
+ $results = $this->buildResults();
+ return $this->filterResultsAgainstTokens($results);
+ }
+
+ protected function renderSpecialTokens(array $values) {
+ return $this->renderTokensFromResults($this->buildResults(), $values);
+ }
+
+ public function buildResults() {
+ $query = new PhabricatorDashboardPortalQuery();
+
+ // TODO: Actually query by name so this scales past 100 portals.
+
+ $portals = $this->executeQuery($query);
+
+ $results = array();
+ foreach ($portals as $portal) {
+ $result = id(new PhabricatorTypeaheadResult())
+ ->setName($portal->getObjectName().' '.$portal->getName())
+ ->setPHID($portal->getPHID())
+ ->setIcon('fa-compass');
+
+ $results[] = $result;
+ }
+
+ return $results;
+ }
+
+}
diff --git a/src/applications/dashboard/xaction/panel/PhabricatorDashboardPanelNameTransaction.php b/src/applications/dashboard/xaction/panel/PhabricatorDashboardPanelNameTransaction.php
new file mode 100644
--- /dev/null
+++ b/src/applications/dashboard/xaction/panel/PhabricatorDashboardPanelNameTransaction.php
@@ -0,0 +1,70 @@
+<?php
+
+final class PhabricatorDashboardPanelNameTransaction
+ extends PhabricatorDashboardPanelTransactionType {
+
+ const TRANSACTIONTYPE = 'dashpanel:name';
+
+ public function generateOldValue($object) {
+ return $object->getName();
+ }
+
+ public function applyInternalEffects($object, $value) {
+ $object->setName($value);
+ }
+
+ public function getTitle() {
+ $old = $this->getOldValue();
+ $new = $this->getNewValue();
+
+ return pht(
+ '%s renamed this panel from %s to %s.',
+ $this->renderAuthor(),
+ $this->renderOldValue(),
+ $this->renderNewValue());
+ }
+
+ public function validateTransactions($object, array $xactions) {
+ $errors = array();
+
+ $max_length = $object->getColumnMaximumByteLength('name');
+ foreach ($xactions as $xaction) {
+ $new = $xaction->getNewValue();
+ if (!strlen($new)) {
+ $errors[] = $this->newInvalidError(
+ pht('Panels must have a title.'),
+ $xaction);
+ continue;
+ }
+
+ if (strlen($new) > $max_length) {
+ $errors[] = $this->newInvalidError(
+ pht(
+ 'Panel names must not be longer than %s characters.',
+ $max_length));
+ continue;
+ }
+ }
+
+ if (!$errors) {
+ if ($this->isEmptyTextTransaction($object->getName(), $xactions)) {
+ $errors[] = $this->newRequiredError(
+ pht('Panels must have a title.'));
+ }
+ }
+
+ return $errors;
+ }
+
+ public function getTransactionTypeForConduit($xaction) {
+ return 'name';
+ }
+
+ public function getFieldValuesForConduit($xaction, $data) {
+ return array(
+ 'old' => $xaction->getOldValue(),
+ 'new' => $xaction->getNewValue(),
+ );
+ }
+
+}
diff --git a/src/applications/dashboard/xaction/panel/PhabricatorDashboardPanelPropertyTransaction.php b/src/applications/dashboard/xaction/panel/PhabricatorDashboardPanelPropertyTransaction.php
new file mode 100644
--- /dev/null
+++ b/src/applications/dashboard/xaction/panel/PhabricatorDashboardPanelPropertyTransaction.php
@@ -0,0 +1,18 @@
+<?php
+
+abstract class PhabricatorDashboardPanelPropertyTransaction
+ extends PhabricatorDashboardPanelTransactionType {
+
+ abstract protected function getPropertyKey();
+
+ public function generateOldValue($object) {
+ $property_key = $this->getPropertyKey();
+ return $object->getProperty($property_key);
+ }
+
+ public function applyInternalEffects($object, $value) {
+ $property_key = $this->getPropertyKey();
+ $object->setProperty($property_key, $value);
+ }
+
+}
diff --git a/src/applications/dashboard/xaction/panel/PhabricatorDashboardPanelStatusTransaction.php b/src/applications/dashboard/xaction/panel/PhabricatorDashboardPanelStatusTransaction.php
new file mode 100644
--- /dev/null
+++ b/src/applications/dashboard/xaction/panel/PhabricatorDashboardPanelStatusTransaction.php
@@ -0,0 +1,33 @@
+<?php
+
+final class PhabricatorDashboardPanelStatusTransaction
+ extends PhabricatorDashboardPanelTransactionType {
+
+ const TRANSACTIONTYPE = 'dashpanel:archive';
+
+ public function generateOldValue($object) {
+ return (bool)$object->getIsArchived();
+ }
+
+ public function generateNewValue($object, $value) {
+ return (bool)$value;
+ }
+
+ public function applyInternalEffects($object, $value) {
+ $object->setIsArchived((int)$value);
+ }
+
+ public function getTitle() {
+ $new = $this->getNewValue();
+ if ($new) {
+ return pht(
+ '%s archived this panel.',
+ $this->renderAuthor());
+ } else {
+ return pht(
+ '%s activated this panel.',
+ $this->renderAuthor());
+ }
+ }
+
+}
diff --git a/src/applications/dashboard/xaction/panel/PhabricatorDashboardPanelTransactionType.php b/src/applications/dashboard/xaction/panel/PhabricatorDashboardPanelTransactionType.php
new file mode 100644
--- /dev/null
+++ b/src/applications/dashboard/xaction/panel/PhabricatorDashboardPanelTransactionType.php
@@ -0,0 +1,4 @@
+<?php
+
+abstract class PhabricatorDashboardPanelTransactionType
+ extends PhabricatorModularTransactionType {}
diff --git a/src/applications/dashboard/xaction/panel/PhabricatorDashboardQueryPanelApplicationTransaction.php b/src/applications/dashboard/xaction/panel/PhabricatorDashboardQueryPanelApplicationTransaction.php
new file mode 100644
--- /dev/null
+++ b/src/applications/dashboard/xaction/panel/PhabricatorDashboardQueryPanelApplicationTransaction.php
@@ -0,0 +1,12 @@
+<?php
+
+final class PhabricatorDashboardQueryPanelApplicationTransaction
+ extends PhabricatorDashboardPanelPropertyTransaction {
+
+ const TRANSACTIONTYPE = 'query.application';
+
+ protected function getPropertyKey() {
+ return 'class';
+ }
+
+}
diff --git a/src/applications/dashboard/xaction/panel/PhabricatorDashboardQueryPanelQueryTransaction.php b/src/applications/dashboard/xaction/panel/PhabricatorDashboardQueryPanelQueryTransaction.php
new file mode 100644
--- /dev/null
+++ b/src/applications/dashboard/xaction/panel/PhabricatorDashboardQueryPanelQueryTransaction.php
@@ -0,0 +1,12 @@
+<?php
+
+final class PhabricatorDashboardQueryPanelQueryTransaction
+ extends PhabricatorDashboardPanelPropertyTransaction {
+
+ const TRANSACTIONTYPE = 'search.query';
+
+ protected function getPropertyKey() {
+ return 'key';
+ }
+
+}
diff --git a/src/applications/dashboard/xaction/panel/PhabricatorDashboardTabsPanelTabsTransaction.php b/src/applications/dashboard/xaction/panel/PhabricatorDashboardTabsPanelTabsTransaction.php
new file mode 100644
--- /dev/null
+++ b/src/applications/dashboard/xaction/panel/PhabricatorDashboardTabsPanelTabsTransaction.php
@@ -0,0 +1,12 @@
+<?php
+
+final class PhabricatorDashboardTabsPanelTabsTransaction
+ extends PhabricatorDashboardPanelPropertyTransaction {
+
+ const TRANSACTIONTYPE = 'tabs.tabs';
+
+ protected function getPropertyKey() {
+ return 'config';
+ }
+
+}
diff --git a/src/applications/dashboard/xaction/panel/PhabricatorDashboardTextPanelTextTransaction.php b/src/applications/dashboard/xaction/panel/PhabricatorDashboardTextPanelTextTransaction.php
new file mode 100644
--- /dev/null
+++ b/src/applications/dashboard/xaction/panel/PhabricatorDashboardTextPanelTextTransaction.php
@@ -0,0 +1,12 @@
+<?php
+
+final class PhabricatorDashboardTextPanelTextTransaction
+ extends PhabricatorDashboardPanelPropertyTransaction {
+
+ const TRANSACTIONTYPE = 'text.text';
+
+ protected function getPropertyKey() {
+ return 'text';
+ }
+
+}
diff --git a/src/applications/differential/herald/DifferentialRevisionJIRAIssueURIsHeraldField.php b/src/applications/differential/herald/DifferentialRevisionJIRAIssueURIsHeraldField.php
new file mode 100644
--- /dev/null
+++ b/src/applications/differential/herald/DifferentialRevisionJIRAIssueURIsHeraldField.php
@@ -0,0 +1,44 @@
+<?php
+
+final class DifferentialRevisionJIRAIssueURIsHeraldField
+ extends DifferentialRevisionHeraldField {
+
+ const FIELDCONST = 'differential.revision.jira.uris';
+
+ public function getHeraldFieldName() {
+ return pht('JIRA Issue URIs');
+ }
+
+ public function supportsObject($object) {
+ $provider = PhabricatorJIRAAuthProvider::getJIRAProvider();
+ if (!$provider) {
+ return false;
+ }
+
+ return parent::supportsObject($object);
+ }
+
+ public function getHeraldFieldValue($object) {
+ $adapter = $this->getAdapter();
+ $viewer = $adapter->getViewer();
+
+ $jira_phids = PhabricatorEdgeQuery::loadDestinationPHIDs(
+ $object->getPHID(),
+ PhabricatorJiraIssueHasObjectEdgeType::EDGECONST);
+ if (!$jira_phids) {
+ return array();
+ }
+
+ $xobjs = id(new DoorkeeperExternalObjectQuery())
+ ->setViewer($viewer)
+ ->withPHIDs($jira_phids)
+ ->execute();
+
+ return mpull($xobjs, 'getObjectURI');
+ }
+
+ protected function getHeraldFieldStandardType() {
+ return self::STANDARD_TEXT_LIST;
+ }
+
+}
diff --git a/src/applications/favorites/application/PhabricatorFavoritesApplication.php b/src/applications/favorites/application/PhabricatorFavoritesApplication.php
--- a/src/applications/favorites/application/PhabricatorFavoritesApplication.php
+++ b/src/applications/favorites/application/PhabricatorFavoritesApplication.php
@@ -15,12 +15,13 @@
}
public function getIcon() {
- return 'fa-star';
+ return 'fa-bookmark';
}
public function getRoutes() {
return array(
'/favorites/' => array(
+ '' => 'PhabricatorFavoritesMenuItemController',
'menu/' => $this->getProfileMenuRouting(
'PhabricatorFavoritesMenuItemController'),
),
diff --git a/src/applications/favorites/controller/PhabricatorFavoritesMenuItemController.php b/src/applications/favorites/controller/PhabricatorFavoritesMenuItemController.php
--- a/src/applications/favorites/controller/PhabricatorFavoritesMenuItemController.php
+++ b/src/applications/favorites/controller/PhabricatorFavoritesMenuItemController.php
@@ -16,8 +16,7 @@
$engine = id(new PhabricatorFavoritesProfileMenuEngine())
->setProfileObject($favorites)
->setCustomPHID($viewer->getPHID())
- ->setController($this)
- ->setShowNavigation(false);
+ ->setController($this);
return $engine->buildResponse();
}
diff --git a/src/applications/favorites/engine/PhabricatorFavoritesProfileMenuEngine.php b/src/applications/favorites/engine/PhabricatorFavoritesProfileMenuEngine.php
--- a/src/applications/favorites/engine/PhabricatorFavoritesProfileMenuEngine.php
+++ b/src/applications/favorites/engine/PhabricatorFavoritesProfileMenuEngine.php
@@ -35,6 +35,10 @@
}
}
+ $items[] = $this->newDividerItem('tail');
+ $items[] = $this->newManageItem()
+ ->setMenuItemProperty('name', pht('Edit Favorites'));
+
return $items;
}
diff --git a/src/applications/favorites/engineextension/PhabricatorFavoritesMainMenuBarExtension.php b/src/applications/favorites/engineextension/PhabricatorFavoritesMainMenuBarExtension.php
--- a/src/applications/favorites/engineextension/PhabricatorFavoritesMainMenuBarExtension.php
+++ b/src/applications/favorites/engineextension/PhabricatorFavoritesMainMenuBarExtension.php
@@ -26,7 +26,7 @@
$favorites_menu = id(new PHUIButtonView())
->setTag('a')
->setHref('#')
- ->setIcon('fa-star')
+ ->setIcon('fa-bookmark')
->addClass('phabricator-core-user-menu')
->setNoCSS(true)
->setDropdown(true)
@@ -71,20 +71,11 @@
$action = id(new PhabricatorActionView())
->setName($item->getName())
->setHref($item->getHref())
+ ->setIcon($item->getIcon())
->setType($item->getType());
$view->addAction($action);
}
- if ($viewer->isLoggedIn()) {
- $view->addAction(
- id(new PhabricatorActionView())
- ->setType(PhabricatorActionView::TYPE_DIVIDER));
- $view->addAction(
- id(new PhabricatorActionView())
- ->setName(pht('Edit Favorites'))
- ->setHref('/favorites/menu/configure/'));
- }
-
return $view;
}
diff --git a/src/applications/home/engine/PhabricatorHomeProfileMenuEngine.php b/src/applications/home/engine/PhabricatorHomeProfileMenuEngine.php
--- a/src/applications/home/engine/PhabricatorHomeProfileMenuEngine.php
+++ b/src/applications/home/engine/PhabricatorHomeProfileMenuEngine.php
@@ -67,11 +67,12 @@
->setMenuItemProperties($properties);
}
- // Hotlink to More Applications Launcher...
$items[] = $this->newItem()
->setBuiltinKey(PhabricatorHomeConstants::ITEM_LAUNCHER)
->setMenuItemKey(PhabricatorHomeLauncherProfileMenuItem::MENUITEMKEY);
+ $items[] = $this->newDividerItem('tail');
+
$items[] = $this->newManageItem();
return $items;
diff --git a/src/applications/people/controller/PhabricatorPeopleProfileEditController.php b/src/applications/people/controller/PhabricatorPeopleProfileEditController.php
--- a/src/applications/people/controller/PhabricatorPeopleProfileEditController.php
+++ b/src/applications/people/controller/PhabricatorPeopleProfileEditController.php
@@ -83,8 +83,9 @@
$crumbs->addTextCrumb(pht('Edit Profile'));
$crumbs->setBorder(true);
- $nav = $this->getProfileMenu();
- $nav->selectFilter(PhabricatorPeopleProfileMenuEngine::ITEM_MANAGE);
+ $nav = $this->newNavigation(
+ $user,
+ PhabricatorPeopleProfileMenuEngine::ITEM_MANAGE);
$header = id(new PHUIHeaderView())
->setHeader(pht('Edit Profile: %s', $user->getFullName()))
diff --git a/src/applications/people/controller/PhabricatorPeopleProfilePictureController.php b/src/applications/people/controller/PhabricatorPeopleProfilePictureController.php
--- a/src/applications/people/controller/PhabricatorPeopleProfilePictureController.php
+++ b/src/applications/people/controller/PhabricatorPeopleProfilePictureController.php
@@ -266,8 +266,9 @@
$crumbs->addTextCrumb(pht('Edit Profile Picture'));
$crumbs->setBorder(true);
- $nav = $this->getProfileMenu();
- $nav->selectFilter(PhabricatorPeopleProfileMenuEngine::ITEM_MANAGE);
+ $nav = $this->newNavigation(
+ $user,
+ PhabricatorPeopleProfileMenuEngine::ITEM_MANAGE);
$header = $this->buildProfileHeader();
diff --git a/src/applications/project/controller/PhabricatorProjectBoardBackgroundController.php b/src/applications/project/controller/PhabricatorProjectBoardBackgroundController.php
--- a/src/applications/project/controller/PhabricatorProjectBoardBackgroundController.php
+++ b/src/applications/project/controller/PhabricatorProjectBoardBackgroundController.php
@@ -52,7 +52,9 @@
->setURI($view_uri);
}
- $nav = $this->getProfileMenu();
+ $nav = $this->newNavigation(
+ $board,
+ PhabricatorProject::ITEM_WORKBOARD);
$crumbs = id($this->buildApplicationCrumbs())
->addTextCrumb(pht('Workboard'), $board->getWorkboardURI())
diff --git a/src/applications/project/controller/PhabricatorProjectBoardManageController.php b/src/applications/project/controller/PhabricatorProjectBoardManageController.php
--- a/src/applications/project/controller/PhabricatorProjectBoardManageController.php
+++ b/src/applications/project/controller/PhabricatorProjectBoardManageController.php
@@ -38,7 +38,9 @@
$crumbs->addTextCrumb(pht('Manage'));
$crumbs->setBorder(true);
- $nav = $this->getProfileMenu();
+ $nav = $this->newNavigation(
+ $board,
+ PhabricatorProject::ITEM_WORKBOARD);
$columns_list = $this->buildColumnsList($board, $columns);
require_celerity_resource('project-view-css');
diff --git a/src/applications/project/controller/PhabricatorProjectColumnDetailController.php b/src/applications/project/controller/PhabricatorProjectColumnDetailController.php
--- a/src/applications/project/controller/PhabricatorProjectColumnDetailController.php
+++ b/src/applications/project/controller/PhabricatorProjectColumnDetailController.php
@@ -51,7 +51,9 @@
$crumbs->addTextCrumb(pht('Column: %s', $title));
$crumbs->setBorder(true);
- $nav = $this->getProfileMenu();
+ $nav = $this->newNavigation(
+ $project,
+ PhabricatorProject::ITEM_WORKBOARD);
require_celerity_resource('project-view-css');
$view = id(new PHUITwoColumnView())
diff --git a/src/applications/project/controller/PhabricatorProjectEditPictureController.php b/src/applications/project/controller/PhabricatorProjectEditPictureController.php
--- a/src/applications/project/controller/PhabricatorProjectEditPictureController.php
+++ b/src/applications/project/controller/PhabricatorProjectEditPictureController.php
@@ -273,8 +273,9 @@
->setHeaderText(pht('Upload New Picture'))
->setForm($upload_form);
- $nav = $this->getProfileMenu();
- $nav->selectFilter(PhabricatorProject::ITEM_MANAGE);
+ $nav = $this->newNavigation(
+ $project,
+ PhabricatorProject::ITEM_MANAGE);
return $this->newPage()
->setTitle($title)
diff --git a/src/applications/project/menuitem/PhabricatorProjectPointsProfileMenuItem.php b/src/applications/project/menuitem/PhabricatorProjectPointsProfileMenuItem.php
--- a/src/applications/project/menuitem/PhabricatorProjectPointsProfileMenuItem.php
+++ b/src/applications/project/menuitem/PhabricatorProjectPointsProfileMenuItem.php
@@ -165,8 +165,9 @@
),
$bar);
- $item = $this->newItemView()
- ->newProgressBar($bar);
+ $item = $this->newItemView();
+
+ $item->newProgressBar($bar);
return array(
$item,
diff --git a/src/applications/project/trigger/PhabricatorProjectTriggerAddProjectsRule.php b/src/applications/project/trigger/PhabricatorProjectTriggerAddProjectsRule.php
new file mode 100644
--- /dev/null
+++ b/src/applications/project/trigger/PhabricatorProjectTriggerAddProjectsRule.php
@@ -0,0 +1,103 @@
+<?php
+
+final class PhabricatorProjectTriggerAddProjectsRule
+ extends PhabricatorProjectTriggerRule {
+
+ const TRIGGERTYPE = 'task.projects.add';
+
+ public function getSelectControLname() {
+ return pht('Add projects');
+ }
+
+ protected function getValueForEditorField() {
+ return $this->getDatasource()->getWireTokens($this->getValue());
+ }
+
+ protected function assertValidRuleValue($value) {
+ if (!is_array($value)) {
+ throw new Exception(
+ pht(
+ 'Add project rule value should be a list, but is not '.
+ '(value is "%s").',
+ phutil_describe_type($value)));
+ }
+ }
+
+ protected function newDropTransactions($object, $value) {
+ $project_edge_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST;
+
+ $xaction = $object->getApplicationTransactionTemplate()
+ ->setTransactionType(PhabricatorTransactions::TYPE_EDGE)
+ ->setMetadataValue('edge:type', $project_edge_type)
+ ->setNewValue(
+ array(
+ '+' => array_fuse($value),
+ ));
+
+ return array($xaction);
+ }
+
+ protected function newDropEffects($value) {
+ return array(
+ $this->newEffect()
+ ->setIcon('fa-briefcase')
+ ->setContent($this->getRuleViewDescription($value)),
+ );
+ }
+
+ protected function getDefaultValue() {
+ return null;
+ }
+
+ protected function getPHUIXControlType() {
+ return 'tokenizer';
+ }
+
+ private function getDatasource() {
+ return id(new PhabricatorProjectDatasource())
+ ->setViewer($this->getViewer());
+ }
+
+ protected function getPHUIXControlSpecification() {
+ $template = id(new AphrontTokenizerTemplateView())
+ ->setViewer($this->getViewer());
+
+ $template_markup = $template->render();
+ $datasource = $this->getDatasource();
+
+ return array(
+ 'markup' => (string)hsprintf('%s', $template_markup),
+ 'config' => array(
+ 'src' => $datasource->getDatasourceURI(),
+ 'browseURI' => $datasource->getBrowseURI(),
+ 'placeholder' => $datasource->getPlaceholderText(),
+ 'limit' => $datasource->getLimit(),
+ ),
+ 'value' => null,
+ );
+ }
+
+ public function getRuleViewLabel() {
+ return pht('Add Projects');
+ }
+
+ public function getRuleViewDescription($value) {
+ return pht(
+ 'Add projects: %s.',
+ phutil_tag(
+ 'strong',
+ array(),
+ $this->getViewer()
+ ->renderHandleList($value)
+ ->setAsInline(true)
+ ->render()));
+ }
+
+ public function getRuleViewIcon($value) {
+ return id(new PHUIIconView())
+ ->setIcon('fa-briefcase', 'green');
+ }
+
+
+
+}
diff --git a/src/applications/project/trigger/PhabricatorProjectTriggerManiphestOwnerRule.php b/src/applications/project/trigger/PhabricatorProjectTriggerManiphestOwnerRule.php
--- a/src/applications/project/trigger/PhabricatorProjectTriggerManiphestOwnerRule.php
+++ b/src/applications/project/trigger/PhabricatorProjectTriggerManiphestOwnerRule.php
@@ -66,7 +66,7 @@
return 'tokenizer';
}
- protected function getDatasource() {
+ private function getDatasource() {
$datasource = id(new ManiphestAssigneeDatasource())
->setLimit(1);
diff --git a/src/applications/search/engine/PhabricatorProfileMenuEngine.php b/src/applications/search/engine/PhabricatorProfileMenuEngine.php
--- a/src/applications/search/engine/PhabricatorProfileMenuEngine.php
+++ b/src/applications/search/engine/PhabricatorProfileMenuEngine.php
@@ -8,7 +8,6 @@
private $items;
private $controller;
private $navigation;
- private $showNavigation = true;
private $editMode;
private $pageClasses = array();
private $showContentCrumbs = true;
@@ -71,15 +70,6 @@
return $this->controller;
}
- public function setShowNavigation($show) {
- $this->showNavigation = $show;
- return $this;
- }
-
- public function getShowNavigation() {
- return $this->showNavigation;
- }
-
public function addContentPageClass($class) {
$this->pageClasses[] = $class;
return $this;
@@ -181,13 +171,19 @@
$crumbs = $controller->buildApplicationCrumbsForEditEngine();
if (!$is_view) {
+ $edit_mode = null;
+
if ($selected_item) {
- if ($selected_item->getCustomPHID()) {
- $edit_mode = 'custom';
- } else {
- $edit_mode = 'global';
+ if ($selected_item->getBuiltinKey() !== self::ITEM_MANAGE) {
+ if ($selected_item->getCustomPHID()) {
+ $edit_mode = 'custom';
+ } else {
+ $edit_mode = 'global';
+ }
}
- } else {
+ }
+
+ if ($edit_mode === null) {
$edit_mode = $request->getURIData('itemEditMode');
}
@@ -309,9 +305,7 @@
$page->setCrumbs($crumbs);
}
- if ($this->getShowNavigation()) {
- $page->setNavigation($navigation);
- }
+ $page->setNavigation($navigation);
if ($is_view) {
foreach ($this->pageClasses as $class) {
@@ -1133,6 +1127,13 @@
->setIsTailItem(true);
}
+ protected function newDividerItem($key) {
+ return $this->newItem()
+ ->setBuiltinKey($key)
+ ->setMenuItemKey(PhabricatorDividerProfileMenuItem::MENUITEMKEY)
+ ->setIsTailItem(true);
+ }
+
public function getDefaultMenuItemConfiguration() {
$configs = $this->getItems();
foreach ($configs as $config) {
diff --git a/src/applications/search/menuitem/PhabricatorDashboardProfileMenuItem.php b/src/applications/search/menuitem/PhabricatorDashboardProfileMenuItem.php
--- a/src/applications/search/menuitem/PhabricatorDashboardProfileMenuItem.php
+++ b/src/applications/search/menuitem/PhabricatorDashboardProfileMenuItem.php
@@ -153,7 +153,7 @@
$icon = $dashboard->getIcon();
$name = $this->getDisplayName($config);
$is_disabled = false;
- $action_uri = '/dashboard/arrange/'.$dashboard->getID().'/';
+ $action_uri = $dashboard->getURI();
}
} else {
$icon = 'fa-ban';
diff --git a/src/applications/search/menuitem/PhabricatorProfileMenuItem.php b/src/applications/search/menuitem/PhabricatorProfileMenuItem.php
--- a/src/applications/search/menuitem/PhabricatorProfileMenuItem.php
+++ b/src/applications/search/menuitem/PhabricatorProfileMenuItem.php
@@ -5,7 +5,6 @@
private $viewer;
private $engine;
-
public function getMenuItemTypeIcon() {
return null;
}
diff --git a/src/applications/transactions/storage/PhabricatorEditEngineConfigurationTransaction.php b/src/applications/transactions/storage/PhabricatorEditEngineConfigurationTransaction.php
--- a/src/applications/transactions/storage/PhabricatorEditEngineConfigurationTransaction.php
+++ b/src/applications/transactions/storage/PhabricatorEditEngineConfigurationTransaction.php
@@ -149,5 +149,19 @@
return parent::getIcon();
}
+ protected function newRemarkupChanges() {
+ $changes = array();
+
+ $type = $this->getTransactionType();
+ switch ($type) {
+ case self::TYPE_PREAMBLE:
+ $changes[] = $this->newRemarkupChange()
+ ->setOldValue($this->getOldValue())
+ ->setNewValue($this->getNewValue());
+ break;
+ }
+
+ return $changes;
+ }
}
diff --git a/src/view/phui/PHUIListItemView.php b/src/view/phui/PHUIListItemView.php
--- a/src/view/phui/PHUIListItemView.php
+++ b/src/view/phui/PHUIListItemView.php
@@ -35,6 +35,7 @@
private $actionIconHref;
private $count;
private $rel;
+ private $hasDropdown;
public function setOpenInNewWindow($open_in_new_window) {
$this->openInNewWindow = $open_in_new_window;
@@ -68,6 +69,7 @@
$this->addSigil('phui-dropdown-menu');
$this->setMetadata($actions->getDropdownMenuMetadata());
+ $this->hasDropdown = true;
return $this;
}
@@ -235,6 +237,10 @@
$classes[] = 'phui-list-item-has-action-icon';
}
+ if ($this->hasDropdown) {
+ $classes[] = 'dropdown';
+ }
+
return array(
'class' => implode(' ', $classes),
);
@@ -363,6 +369,12 @@
$this->count);
}
+ if ($this->hasDropdown) {
+ $caret = phutil_tag('span', array('class' => 'caret'), '');
+ } else {
+ $caret = null;
+ }
+
$icons = $this->getIcons();
$list_item = javelin_tag(
@@ -381,6 +393,7 @@
$icons,
$this->renderChildren(),
$name,
+ $caret,
$count,
));
diff --git a/src/view/phui/PHUIObjectItemView.php b/src/view/phui/PHUIObjectItemView.php
--- a/src/view/phui/PHUIObjectItemView.php
+++ b/src/view/phui/PHUIObjectItemView.php
@@ -299,6 +299,8 @@
if ($this->disabled) {
$item_classes[] = 'phui-oi-disabled';
+ } else {
+ $item_classes[] = 'phui-oi-enabled';
}
switch ($this->effect) {
diff --git a/webroot/rsrc/css/application/base/main-menu-view.css b/webroot/rsrc/css/application/base/main-menu-view.css
--- a/webroot/rsrc/css/application/base/main-menu-view.css
+++ b/webroot/rsrc/css/application/base/main-menu-view.css
@@ -650,6 +650,7 @@
ul.phabricator-core-user-profile-object .phui-oi-subhead {
padding: 0;
margin: 0;
+ background: transparent;
}
ul.phabricator-core-user-profile-object.phui-oi-list-simple .phui-oi-image {
diff --git a/webroot/rsrc/css/application/dashboard/dashboard.css b/webroot/rsrc/css/application/dashboard/dashboard.css
--- a/webroot/rsrc/css/application/dashboard/dashboard.css
+++ b/webroot/rsrc/css/application/dashboard/dashboard.css
@@ -54,7 +54,7 @@
}
.grippable .aphront-multi-column-column .dashboard-box.phui-object-box:hover {
- box-shadow: {$dropshadow};
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.10);
}
.grippable .aphront-multi-column-column .dashboard-box.phui-object-box:hover
diff --git a/webroot/rsrc/css/phui/object-item/phui-oi-big-ui.css b/webroot/rsrc/css/phui/object-item/phui-oi-big-ui.css
--- a/webroot/rsrc/css/phui/object-item/phui-oi-big-ui.css
+++ b/webroot/rsrc/css/phui/object-item/phui-oi-big-ui.css
@@ -70,21 +70,29 @@
}
.phui-oi-list-big .phui-oi-linked-container {
- border: 1px solid {$lightblueborder};
+ border-width: 1px;
+ border-style: solid;
border-radius: 4px;
- box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.035);
}
-.phui-oi-list-big .phui-oi-disabled {
- border-radius: 4px;
- background: {$lightgreybackground};
+.phui-oi-list-big .phui-oi-enabled.phui-oi-linked-container {
+ border-color: {$lightblueborder};
+ box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.05);
+}
+
+.phui-oi-list-big .phui-oi-disabled.phui-oi-linked-container {
+ border-color: {$greybackground};
+}
+
+.phui-oi-list-big .phui-oi-disabled .phui-oi-image-icon .phui-icon-view {
+ color: {$darkgreybackground};
}
.device-desktop .phui-oi-linked-container {
cursor: pointer;
}
-.device-desktop .phui-oi-linked-container:hover {
+.device-desktop .phui-oi-enabled.phui-oi-linked-container:hover {
background-color: {$hoverblue};
border-color: {$blueborder};
}
diff --git a/webroot/rsrc/css/phui/phui-action-list.css b/webroot/rsrc/css/phui/phui-action-list.css
--- a/webroot/rsrc/css/phui/phui-action-list.css
+++ b/webroot/rsrc/css/phui/phui-action-list.css
@@ -213,3 +213,14 @@
.phabricator-action-view-item .phui-icon-view {
color: {$sky};
}
+
+.phui-list-navbar .phui-list-item-view.dropdown .phui-list-item-href {
+ padding-right: 28px;
+}
+
+.phui-list-navbar .phui-list-item-view .caret {
+ position: absolute;
+ top: 6px;
+ right: 12px;
+ border-top: 7px solid {$greytext};
+}
diff --git a/webroot/rsrc/js/phuix/PHUIXDropdownMenu.js b/webroot/rsrc/js/phuix/PHUIXDropdownMenu.js
--- a/webroot/rsrc/js/phuix/PHUIXDropdownMenu.js
+++ b/webroot/rsrc/js/phuix/PHUIXDropdownMenu.js
@@ -198,7 +198,35 @@
var v = JX.$V(this._node);
var d = JX.Vector.getDim(this._node);
- switch (this.getAlign()) {
+ var alignments = ['right', 'left'];
+ var disallow = {};
+ var margin = 8;
+
+ // If "right" alignment would leave us with the dropdown near or off the
+ // left side of the screen, disallow it.
+ var x_min = ((v.x + d.x) - m.x);
+ if (x_min < margin) {
+ disallow.right = true;
+ }
+
+ var align = this.getAlign();
+
+ // If the position disallows the configured alignment, try the next
+ // best alignment instead.
+
+ // If no alignment is allowed, we'll stick with the original alignment
+ // and accept that it isn't going to render very nicely. This can happen
+ // if the browser window is very, very small.
+ if (align in disallow) {
+ for (var ii = 0; ii < alignments.length; ii++) {
+ if (!(alignments[ii] in disallow)) {
+ align = alignments[ii];
+ break;
+ }
+ }
+ }
+
+ switch (align) {
case 'right':
v = v.add(d)
.add(JX.$V(-m.x, 0));

File Metadata

Mime Type
text/plain
Expires
Fri, Mar 21, 3:46 AM (2 w, 3 d ago)
Storage Engine
amazon-s3
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
phabricator/secure/rl/b5/xcywiky34ejoomgw
Default Alt Text
D20379.id48657.diff (182 KB)

Event Timeline