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' => '2d4810eb', + 'core.pkg.js' => 'c783d8f6', 'differential.pkg.css' => '8d8360fb', 'differential.pkg.js' => '67e02996', 'diffusion.pkg.css' => '42c75c37', @@ -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,7 +128,7 @@ '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', @@ -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', @@ -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', @@ -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', @@ -1379,9 +1379,6 @@ 'javelin-dom', 'javelin-fx', ), - '534f1757' => array( - 'phui-oi-list-view-css', - ), '541f81c3' => array( 'javelin-install', ), @@ -1566,6 +1563,13 @@ 'javelin-install', 'javelin-dom', ), + '7acfd98b' => array( + 'javelin-install', + 'javelin-util', + 'javelin-dom', + 'javelin-vector', + 'javelin-stratcom', + ), '7ad020a5' => 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 @@ -2905,54 +2905,57 @@ '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', '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,8 +2971,13 @@ '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', @@ -2977,11 +2985,12 @@ 'PhabricatorDashboardSchemaSpec' => 'applications/dashboard/storage/PhabricatorDashboardSchemaSpec.php', 'PhabricatorDashboardSearchEngine' => 'applications/dashboard/query/PhabricatorDashboardSearchEngine.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 +4205,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', @@ -8867,8 +8877,8 @@ ), 'PhabricatorDashboardAddPanelController' => 'PhabricatorDashboardController', 'PhabricatorDashboardApplication' => 'PhabricatorApplication', + 'PhabricatorDashboardApplicationInstallWorkflow' => 'PhabricatorDashboardInstallWorkflow', 'PhabricatorDashboardArchiveController' => 'PhabricatorDashboardController', - 'PhabricatorDashboardArrangeController' => 'PhabricatorDashboardProfileController', 'PhabricatorDashboardConsoleController' => 'PhabricatorDashboardController', 'PhabricatorDashboardController' => 'PhabricatorController', 'PhabricatorDashboardDAO' => 'PhabricatorLiskDAO', @@ -8876,48 +8886,45 @@ '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', + 'PhabricatorDashboardPanelTransaction' => 'PhabricatorModularTransaction', 'PhabricatorDashboardPanelTransactionEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorDashboardPanelTransactionQuery' => 'PhabricatorApplicationTransactionQuery', + 'PhabricatorDashboardPanelTransactionType' => 'PhabricatorModularTransactionType', 'PhabricatorDashboardPanelType' => 'Phobject', 'PhabricatorDashboardPanelViewController' => 'PhabricatorDashboardController', 'PhabricatorDashboardPortal' => array( @@ -8927,10 +8934,12 @@ 'PhabricatorDestructibleInterface', ), 'PhabricatorDashboardPortalController' => 'PhabricatorDashboardController', + 'PhabricatorDashboardPortalDatasource' => 'PhabricatorTypeaheadDatasource', 'PhabricatorDashboardPortalEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod', 'PhabricatorDashboardPortalEditController' => 'PhabricatorDashboardPortalController', 'PhabricatorDashboardPortalEditEngine' => 'PhabricatorEditEngine', 'PhabricatorDashboardPortalEditor' => 'PhabricatorApplicationTransactionEditor', + 'PhabricatorDashboardPortalInstallWorkflow' => 'PhabricatorDashboardObjectInstallWorkflow', 'PhabricatorDashboardPortalListController' => 'PhabricatorDashboardPortalController', 'PhabricatorDashboardPortalMenuItem' => 'PhabricatorProfileMenuItem', 'PhabricatorDashboardPortalNameTransaction' => 'PhabricatorDashboardPortalTransactionType', @@ -8946,8 +8955,13 @@ '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', @@ -8955,6 +8969,7 @@ 'PhabricatorDashboardSchemaSpec' => 'PhabricatorConfigSchemaSpec', 'PhabricatorDashboardSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorDashboardTabsPanelType' => 'PhabricatorDashboardPanelType', + 'PhabricatorDashboardTextPanelTextTransaction' => 'PhabricatorDashboardPanelPropertyTransaction', 'PhabricatorDashboardTextPanelType' => 'PhabricatorDashboardPanelType', 'PhabricatorDashboardTransaction' => 'PhabricatorApplicationTransaction', 'PhabricatorDashboardTransactionEditor' => 'PhabricatorApplicationTransactionEditor', @@ -10363,6 +10378,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\d+)/' => 'PhabricatorDashboardViewController', 'archive/(?P\d+)/' => 'PhabricatorDashboardArchiveController', - 'manage/(?P\d+)/' => 'PhabricatorDashboardManageController', - 'arrange/(?P\d+)/' => 'PhabricatorDashboardArrangeController', 'create/' => 'PhabricatorDashboardEditController', 'edit/(?:(?P\d+)/)?' => 'PhabricatorDashboardEditController', - 'install/(?:(?P\d+)/)?' => 'PhabricatorDashboardInstallController', + 'install/(?P\d+)/'. + '(?:(?P[^/]+)/'. + '(?:(?P[^/]+)/)?)?' => + 'PhabricatorDashboardInstallController', 'console/' => 'PhabricatorDashboardConsoleController', 'addpanel/(?P\d+)/' => 'PhabricatorDashboardAddPanelController', 'movepanel/(?P\d+)/' => 'PhabricatorDashboardMovePanelController', @@ -56,10 +57,8 @@ 'PhabricatorDashboardQueryPanelInstallController', '(?:query/(?P[^/]+)/)?' => 'PhabricatorDashboardPanelListController', - 'create/' => 'PhabricatorDashboardPanelEditController', - $this->getEditRoutePattern('editpro/') - => 'PhabricatorDashboardPanelEditproController', - 'edit/(?:(?P\d+)/)?' => 'PhabricatorDashboardPanelEditController', + $this->getEditRoutePattern('edit/') + => 'PhabricatorDashboardPanelEditController', 'render/(?P\d+)/' => 'PhabricatorDashboardPanelRenderController', 'archive/(?P\d+)/' => 'PhabricatorDashboardPanelArchiveController', 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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ +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 @@ 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 @@ +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/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 @@ -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 @@ -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 @@ 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 @@ 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,15 @@ return $this->headerMode; } + public function setPanelHandle(PhabricatorObjectHandle $panel_handle) { + $this->panelHandle = $panel_handle; + return $this; + } + + public function getPanelHandle() { + return $this->panelHandle; + } + /** * Allow the engine to render the panel via Ajax. */ @@ -90,11 +100,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 +203,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 +275,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 +299,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 +315,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 +333,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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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 @@ +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,16 @@ } 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) { + // TODO: Restore this using EditEngine instead of CustomField. + return array(); } public function shouldRenderAsync() { 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 @@ 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/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 @@ +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 @@ +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 @@ +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 @@ +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 @@ + 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 @@ +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/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/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/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));