1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-12-13 09:06:14 +01:00

(stable) Promote 2019 Week 16

This commit is contained in:
epriestley 2019-04-17 18:53:13 -07:00
commit f040a591e6
289 changed files with 7967 additions and 4389 deletions

View file

@ -9,8 +9,8 @@ return array(
'names' => array(
'conpherence.pkg.css' => '3c8a0668',
'conpherence.pkg.js' => '020aebcf',
'core.pkg.css' => '7e6e954b',
'core.pkg.js' => 'a747b035',
'core.pkg.css' => '3dc188c0',
'core.pkg.js' => '9ac8af68',
'differential.pkg.css' => '8d8360fb',
'differential.pkg.js' => '67e02996',
'diffusion.pkg.css' => '42c75c37',
@ -30,14 +30,14 @@ return array(
'rsrc/css/aphront/notification.css' => '30240bd2',
'rsrc/css/aphront/panel-view.css' => '46923d46',
'rsrc/css/aphront/phabricator-nav-view.css' => 'f8a0c1bf',
'rsrc/css/aphront/table-view.css' => '7dc3a9c2',
'rsrc/css/aphront/table-view.css' => '5f13a9e4',
'rsrc/css/aphront/tokenizer.css' => 'b52d0668',
'rsrc/css/aphront/tooltip.css' => 'e3f2412f',
'rsrc/css/aphront/typeahead-browse.css' => 'b7ed02d2',
'rsrc/css/aphront/typeahead.css' => '8779483d',
'rsrc/css/application/almanac/almanac.css' => '2e050f4f',
'rsrc/css/application/auth/auth.css' => 'add92fd8',
'rsrc/css/application/base/main-menu-view.css' => '8e2d9a28',
'rsrc/css/application/base/main-menu-view.css' => '17b71bbc',
'rsrc/css/application/base/notification-menu.css' => '4df1ee30',
'rsrc/css/application/base/phui-theme.css' => '35883b37',
'rsrc/css/application/base/standard-page-view.css' => '8a295cb9',
@ -58,7 +58,7 @@ return array(
'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',
@ -86,7 +86,7 @@ return array(
'rsrc/css/application/paste/paste.css' => 'b37bcd38',
'rsrc/css/application/people/people-picture-menu-item.css' => 'fe8e07cf',
'rsrc/css/application/people/people-profile.css' => '2ea2daa1',
'rsrc/css/application/phame/phame.css' => '799febf9',
'rsrc/css/application/phame/phame.css' => 'bb442327',
'rsrc/css/application/pholio/pholio-edit.css' => '4df55b3b',
'rsrc/css/application/pholio/pholio-inline-comments.css' => '722b48c2',
'rsrc/css/application/pholio/pholio.css' => '88ef5ef1',
@ -100,7 +100,7 @@ return array(
'rsrc/css/application/policy/policy.css' => 'ceb56a08',
'rsrc/css/application/ponder/ponder-view.css' => '05a09d0a',
'rsrc/css/application/project/project-card-view.css' => '4e7371cd',
'rsrc/css/application/project/project-triggers.css' => 'cb866c2d',
'rsrc/css/application/project/project-triggers.css' => 'cd9c8bb9',
'rsrc/css/application/project/project-view.css' => '567858b3',
'rsrc/css/application/releeph/releeph-core.css' => 'f81ff2db',
'rsrc/css/application/releeph/releeph-preview-branch.css' => '22db5c07',
@ -128,13 +128,13 @@ return array(
'rsrc/css/phui/calendar/phui-calendar-list.css' => 'ccd7e4e2',
'rsrc/css/phui/calendar/phui-calendar-month.css' => 'cb758c42',
'rsrc/css/phui/calendar/phui-calendar.css' => 'f11073aa',
'rsrc/css/phui/object-item/phui-oi-big-ui.css' => '534f1757',
'rsrc/css/phui/object-item/phui-oi-big-ui.css' => 'fa74cc35',
'rsrc/css/phui/object-item/phui-oi-color.css' => 'b517bfa0',
'rsrc/css/phui/object-item/phui-oi-drag-ui.css' => 'da15d3dc',
'rsrc/css/phui/object-item/phui-oi-flush-ui.css' => '490e2e2e',
'rsrc/css/phui/object-item/phui-oi-list-view.css' => 'a65865a7',
'rsrc/css/phui/object-item/phui-oi-list-view.css' => 'd7723ecc',
'rsrc/css/phui/object-item/phui-oi-simple-ui.css' => '6a30fa46',
'rsrc/css/phui/phui-action-list.css' => 'c4972757',
'rsrc/css/phui/phui-action-list.css' => 'e820263c',
'rsrc/css/phui/phui-action-panel.css' => '6c386cbf',
'rsrc/css/phui/phui-badge.css' => '666e25ad',
'rsrc/css/phui/phui-basic-nav-view.css' => '56ebd66d',
@ -160,11 +160,11 @@ return array(
'rsrc/css/phui/phui-icon-set-selector.css' => '7aa5f3ec',
'rsrc/css/phui/phui-icon.css' => '4cbc684a',
'rsrc/css/phui/phui-image-mask.css' => '62c7f4d2',
'rsrc/css/phui/phui-info-view.css' => '37b8d9ce',
'rsrc/css/phui/phui-info-view.css' => 'a10a909b',
'rsrc/css/phui/phui-invisible-character-view.css' => 'c694c4a4',
'rsrc/css/phui/phui-left-right.css' => '68513c34',
'rsrc/css/phui/phui-lightbox.css' => '4ebf22da',
'rsrc/css/phui/phui-list.css' => '470b1adb',
'rsrc/css/phui/phui-list.css' => 'b05144dd',
'rsrc/css/phui/phui-object-box.css' => 'f434b6be',
'rsrc/css/phui/phui-pager.css' => 'd022c7ad',
'rsrc/css/phui/phui-pinboard-view.css' => '1f08f5d8',
@ -173,7 +173,7 @@ return array(
'rsrc/css/phui/phui-segment-bar-view.css' => '5166b370',
'rsrc/css/phui/phui-spacing.css' => 'b05cadc3',
'rsrc/css/phui/phui-status.css' => 'e5ff8be0',
'rsrc/css/phui/phui-tag-view.css' => '29409667',
'rsrc/css/phui/phui-tag-view.css' => '8519160a',
'rsrc/css/phui/phui-timeline-view.css' => '1e348e4b',
'rsrc/css/phui/phui-two-column-view.css' => '01e6991e',
'rsrc/css/phui/workboards/phui-workboard-color.css' => 'e86de308',
@ -217,7 +217,7 @@ return array(
'rsrc/externals/javelin/core/init.js' => '98e6504a',
'rsrc/externals/javelin/core/init_node.js' => '16961339',
'rsrc/externals/javelin/core/install.js' => '5902260c',
'rsrc/externals/javelin/core/util.js' => '22ae1776',
'rsrc/externals/javelin/core/util.js' => 'edb4d8c9',
'rsrc/externals/javelin/docs/Base.js' => '5a401d7d',
'rsrc/externals/javelin/docs/onload.js' => 'ee58fb62',
'rsrc/externals/javelin/ext/fx/Color.js' => '78f811c9',
@ -259,7 +259,7 @@ return array(
'rsrc/externals/javelin/lib/__tests__/JSON.js' => '710377ae',
'rsrc/externals/javelin/lib/__tests__/URI.js' => '6fff0c2b',
'rsrc/externals/javelin/lib/__tests__/behavior.js' => '8426ebeb',
'rsrc/externals/javelin/lib/behavior.js' => 'fce5d170',
'rsrc/externals/javelin/lib/behavior.js' => '1b6acc2a',
'rsrc/externals/javelin/lib/control/tokenizer/Tokenizer.js' => '89a1ae3a',
'rsrc/externals/javelin/lib/control/typeahead/Typeahead.js' => 'a4356cde',
'rsrc/externals/javelin/lib/control/typeahead/normalizer/TypeaheadNormalizer.js' => 'a241536a',
@ -371,10 +371,10 @@ return array(
'rsrc/js/application/conpherence/behavior-toggle-widget.js' => '8f959ad0',
'rsrc/js/application/countdown/timer.js' => '6a162524',
'rsrc/js/application/daemon/behavior-bulk-job-reload.js' => '3829a3cf',
'rsrc/js/application/dashboard/behavior-dashboard-async-panel.js' => '09ecf50c',
'rsrc/js/application/dashboard/behavior-dashboard-move-panels.js' => '076bd092',
'rsrc/js/application/dashboard/behavior-dashboard-async-panel.js' => '9c01e364',
'rsrc/js/application/dashboard/behavior-dashboard-move-panels.js' => 'a2ab19be',
'rsrc/js/application/dashboard/behavior-dashboard-query-panel-select.js' => '1e413dc9',
'rsrc/js/application/dashboard/behavior-dashboard-tab-panel.js' => '9b1cbd76',
'rsrc/js/application/dashboard/behavior-dashboard-tab-panel.js' => '0116d3e8',
'rsrc/js/application/diff/DiffChangeset.js' => 'd0a85a85',
'rsrc/js/application/diff/DiffChangesetList.js' => '04023d82',
'rsrc/js/application/diff/DiffInline.js' => 'a4a14a94',
@ -433,7 +433,7 @@ return array(
'rsrc/js/application/transactions/behavior-show-older-transactions.js' => '600f440c',
'rsrc/js/application/transactions/behavior-transaction-comment-form.js' => '2bdadf1a',
'rsrc/js/application/transactions/behavior-transaction-list.js' => '9cec214e',
'rsrc/js/application/trigger/TriggerRule.js' => '1c60c3fc',
'rsrc/js/application/trigger/TriggerRule.js' => '41b7b4f6',
'rsrc/js/application/trigger/TriggerRuleControl.js' => '5faf27b9',
'rsrc/js/application/trigger/TriggerRuleEditor.js' => 'b49fd60c',
'rsrc/js/application/trigger/TriggerRuleType.js' => '4feea7d3',
@ -516,9 +516,9 @@ return array(
'rsrc/js/phui/behavior-phui-timer-control.js' => 'f84bcbf4',
'rsrc/js/phuix/PHUIXActionListView.js' => 'c68f183f',
'rsrc/js/phuix/PHUIXActionView.js' => 'aaa08f3b',
'rsrc/js/phuix/PHUIXAutocomplete.js' => '8f139ef0',
'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',
@ -531,7 +531,7 @@ return array(
'aphront-list-filter-view-css' => 'feb64255',
'aphront-multi-column-view-css' => 'fbc00ba3',
'aphront-panel-view-css' => '46923d46',
'aphront-table-view-css' => '7dc3a9c2',
'aphront-table-view-css' => '5f13a9e4',
'aphront-tokenizer-control-css' => 'b52d0668',
'aphront-tooltip-css' => 'e3f2412f',
'aphront-typeahead-control-css' => '8779483d',
@ -571,7 +571,7 @@ return array(
'herald-test-css' => 'e004176f',
'inline-comment-summary-css' => '81eb368d',
'javelin-aphlict' => '022516b4',
'javelin-behavior' => 'fce5d170',
'javelin-behavior' => '1b6acc2a',
'javelin-behavior-aphlict-dropdown' => 'e9a2940f',
'javelin-behavior-aphlict-listen' => '4e61fa88',
'javelin-behavior-aphlict-status' => 'c3703a16',
@ -594,10 +594,10 @@ return array(
'javelin-behavior-conpherence-search' => '91befbcc',
'javelin-behavior-countdown-timer' => '6a162524',
'javelin-behavior-dark-console' => 'f39d968b',
'javelin-behavior-dashboard-async-panel' => '09ecf50c',
'javelin-behavior-dashboard-move-panels' => '076bd092',
'javelin-behavior-dashboard-async-panel' => '9c01e364',
'javelin-behavior-dashboard-move-panels' => 'a2ab19be',
'javelin-behavior-dashboard-query-panel-select' => '1e413dc9',
'javelin-behavior-dashboard-tab-panel' => '9b1cbd76',
'javelin-behavior-dashboard-tab-panel' => '0116d3e8',
'javelin-behavior-day-view' => '727a5a61',
'javelin-behavior-desktop-notifications-control' => '070679fe',
'javelin-behavior-detect-timezone' => '78bc5d94',
@ -729,7 +729,7 @@ return array(
'javelin-typeahead-source' => '8badee71',
'javelin-typeahead-static-source' => '80bff3af',
'javelin-uri' => '2e255291',
'javelin-util' => '22ae1776',
'javelin-util' => 'edb4d8c9',
'javelin-vector' => 'e9c80beb',
'javelin-view' => '289bf236',
'javelin-view-html' => 'f8c4e135',
@ -757,7 +757,7 @@ return array(
'path-typeahead' => 'ad486db3',
'people-picture-menu-item-css' => 'fe8e07cf',
'people-profile-css' => '2ea2daa1',
'phabricator-action-list-view-css' => 'c4972757',
'phabricator-action-list-view-css' => 'e820263c',
'phabricator-busy' => '5202e831',
'phabricator-chatlog-css' => 'abdc76ee',
'phabricator-content-source-view-css' => 'cdf0d579',
@ -765,7 +765,7 @@ return array(
'phabricator-countdown-css' => 'bff8012f',
'phabricator-darklog' => '3b869402',
'phabricator-darkmessage' => '26cd4b73',
'phabricator-dashboard-css' => '4267d6c6',
'phabricator-dashboard-css' => '5a205b9d',
'phabricator-diff-changeset' => 'd0a85a85',
'phabricator-diff-changeset-list' => '04023d82',
'phabricator-diff-inline' => 'a4a14a94',
@ -779,7 +779,7 @@ return array(
'phabricator-flag-css' => '2b77be8d',
'phabricator-keyboard-shortcut' => 'c9749dcd',
'phabricator-keyboard-shortcut-manager' => '37b8a04a',
'phabricator-main-menu-view' => '8e2d9a28',
'phabricator-main-menu-view' => '17b71bbc',
'phabricator-nav-view-css' => 'f8a0c1bf',
'phabricator-notification' => 'a9b91e3f',
'phabricator-notification-css' => '30240bd2',
@ -798,7 +798,7 @@ return array(
'phabricator-tooltip' => '83754533',
'phabricator-ui-example-css' => 'b4795059',
'phabricator-zindex-css' => '99c0f5eb',
'phame-css' => '799febf9',
'phame-css' => 'bb442327',
'pholio-css' => '88ef5ef1',
'pholio-edit-css' => '4df55b3b',
'pholio-inline-comments-css' => '722b48c2',
@ -842,18 +842,18 @@ return array(
'phui-icon-set-selector-css' => '7aa5f3ec',
'phui-icon-view-css' => '4cbc684a',
'phui-image-mask-css' => '62c7f4d2',
'phui-info-view-css' => '37b8d9ce',
'phui-info-view-css' => 'a10a909b',
'phui-inline-comment-view-css' => '48acce5b',
'phui-invisible-character-view-css' => 'c694c4a4',
'phui-left-right-css' => '68513c34',
'phui-lightbox-css' => '4ebf22da',
'phui-list-view-css' => '470b1adb',
'phui-list-view-css' => 'b05144dd',
'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',
'phui-oi-list-view-css' => 'a65865a7',
'phui-oi-list-view-css' => 'd7723ecc',
'phui-oi-simple-ui-css' => '6a30fa46',
'phui-pager-css' => 'd022c7ad',
'phui-pinboard-view-css' => '1f08f5d8',
@ -862,7 +862,7 @@ return array(
'phui-segment-bar-view-css' => '5166b370',
'phui-spacing-css' => 'b05cadc3',
'phui-status-list-view-css' => 'e5ff8be0',
'phui-tag-view-css' => '29409667',
'phui-tag-view-css' => '8519160a',
'phui-theme-css' => '35883b37',
'phui-timeline-view-css' => '1e348e4b',
'phui-two-column-view-css' => '01e6991e',
@ -872,9 +872,9 @@ return array(
'phui-workpanel-view-css' => '3ae89b20',
'phuix-action-list-view' => 'c68f183f',
'phuix-action-view' => 'aaa08f3b',
'phuix-autocomplete' => '8f139ef0',
'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',
@ -882,7 +882,7 @@ return array(
'policy-transaction-detail-css' => 'c02b8384',
'ponder-view-css' => '05a09d0a',
'project-card-view-css' => '4e7371cd',
'project-triggers-css' => 'cb866c2d',
'project-triggers-css' => 'cd9c8bb9',
'project-view-css' => '567858b3',
'releeph-core' => 'f81ff2db',
'releeph-preview-branch' => '22db5c07',
@ -894,7 +894,7 @@ return array(
'syntax-default-css' => '055fc231',
'syntax-highlighting-css' => '4234f572',
'tokens-css' => 'ce5a50bd',
'trigger-rule' => '1c60c3fc',
'trigger-rule' => '41b7b4f6',
'trigger-rule-control' => '5faf27b9',
'trigger-rule-editor' => 'b49fd60c',
'trigger-rule-type' => '4feea7d3',
@ -902,6 +902,11 @@ return array(
'unhandled-exception-css' => '9ecfc00d',
),
'requires' => array(
'0116d3e8' => array(
'javelin-behavior',
'javelin-dom',
'javelin-stratcom',
),
'01384686' => array(
'javelin-behavior',
'javelin-uri',
@ -959,14 +964,6 @@ return array(
'javelin-request',
'javelin-uri',
),
'076bd092' => array(
'javelin-behavior',
'javelin-dom',
'javelin-util',
'javelin-stratcom',
'javelin-workflow',
'phabricator-draggable-list',
),
'0889b835' => array(
'javelin-install',
'javelin-event',
@ -977,11 +974,6 @@ return array(
'herald-rule-editor',
'javelin-behavior',
),
'09ecf50c' => array(
'javelin-behavior',
'javelin-dom',
'javelin-workflow',
),
'0ad8d31f' => array(
'javelin-behavior',
'javelin-stratcom',
@ -1029,6 +1021,13 @@ return array(
'javelin-stratcom',
'javelin-util',
),
'17b71bbc' => array(
'phui-theme-css',
),
'1b6acc2a' => array(
'javelin-magical-init',
'javelin-util',
),
'1c850a26' => array(
'javelin-install',
'javelin-util',
@ -1173,6 +1172,12 @@ return array(
'phuix-autocomplete',
'javelin-mask',
),
'2fbe234d' => array(
'javelin-install',
'javelin-dom',
'phuix-icon-view',
'phabricator-prefab',
),
'308f9fe4' => array(
'javelin-install',
'javelin-util',
@ -1369,9 +1374,6 @@ return array(
'javelin-dom',
'javelin-fx',
),
'534f1757' => array(
'phui-oi-list-view-css',
),
'541f81c3' => array(
'javelin-install',
),
@ -1556,6 +1558,13 @@ return array(
'javelin-install',
'javelin-dom',
),
'7acfd98b' => array(
'javelin-install',
'javelin-util',
'javelin-dom',
'javelin-vector',
'javelin-stratcom',
),
'7ad020a5' => array(
'javelin-behavior',
'javelin-dom',
@ -1631,15 +1640,6 @@ return array(
'javelin-install',
'javelin-dom',
),
'8e2d9a28' => array(
'phui-theme-css',
),
'8f139ef0' => array(
'javelin-install',
'javelin-dom',
'phuix-icon-view',
'phabricator-prefab',
),
'8f959ad0' => array(
'javelin-behavior',
'javelin-dom',
@ -1728,10 +1728,10 @@ return array(
'javelin-install',
'javelin-util',
),
'9b1cbd76' => array(
'9c01e364' => array(
'javelin-behavior',
'javelin-dom',
'javelin-stratcom',
'javelin-workflow',
),
'9cec214e' => array(
'javelin-behavior',
@ -1757,6 +1757,14 @@ return array(
'a241536a' => array(
'javelin-install',
),
'a2ab19be' => array(
'javelin-behavior',
'javelin-dom',
'javelin-util',
'javelin-stratcom',
'javelin-workflow',
'phabricator-draggable-list',
),
'a4356cde' => array(
'javelin-install',
'javelin-dom',
@ -1921,13 +1929,6 @@ return array(
'javelin-uri',
'phabricator-notification',
),
'bdce4d78' => array(
'javelin-install',
'javelin-util',
'javelin-dom',
'javelin-vector',
'javelin-stratcom',
),
'bde53589' => array(
'phui-inline-comment-view-css',
),
@ -2175,9 +2176,8 @@ return array(
'phabricator-keyboard-shortcut',
'conpherence-thread-manager',
),
'fce5d170' => array(
'javelin-magical-init',
'javelin-util',
'fa74cc35' => array(
'phui-oi-list-view-css',
),
'fdc13e4e' => array(
'javelin-install',

View file

@ -0,0 +1,11 @@
CREATE TABLE {$NAMESPACE}_dashboard.dashboard_portal (
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
phid VARBINARY(64) NOT NULL,
name VARCHAR(255) NOT NULL COLLATE {$COLLATE_TEXT},
status VARCHAR(32) NOT NULL COLLATE {$COLLATE_TEXT},
viewPolicy VARBINARY(64) NOT NULL,
editPolicy VARBINARY(64) NOT NULL,
properties LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT},
dateCreated INT UNSIGNED NOT NULL,
dateModified INT UNSIGNED NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE {$COLLATE_TEXT};

View file

@ -0,0 +1,19 @@
CREATE TABLE {$NAMESPACE}_dashboard.dashboard_portaltransaction (
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
phid VARBINARY(64) NOT NULL,
authorPHID VARBINARY(64) NOT NULL,
objectPHID VARBINARY(64) NOT NULL,
viewPolicy VARBINARY(64) NOT NULL,
editPolicy VARBINARY(64) NOT NULL,
commentPHID VARBINARY(64) DEFAULT NULL,
commentVersion INT UNSIGNED NOT NULL,
transactionType VARCHAR(32) NOT NULL,
oldValue LONGTEXT NOT NULL,
newValue LONGTEXT NOT NULL,
contentSource LONGTEXT NOT NULL,
metadata LONGTEXT NOT NULL,
dateCreated INT UNSIGNED NOT NULL,
dateModified INT UNSIGNED NOT NULL,
UNIQUE KEY `key_phid` (`phid`),
KEY `key_object` (`objectPHID`)
) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE {$COLLATE_TEXT};

View file

@ -0,0 +1,9 @@
CREATE TABLE {$NAMESPACE}_dashboard.dashboard_portal_fdocument (
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
objectPHID VARBINARY(64) NOT NULL,
isClosed BOOL NOT NULL,
authorPHID VARBINARY(64),
ownerPHID VARBINARY(64),
epochCreated INT UNSIGNED NOT NULL,
epochModified INT UNSIGNED NOT NULL
) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};

View file

@ -0,0 +1,8 @@
CREATE TABLE {$NAMESPACE}_dashboard.dashboard_portal_ffield (
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
documentID INT UNSIGNED NOT NULL,
fieldKey VARCHAR(4) NOT NULL COLLATE {$COLLATE_TEXT},
rawCorpus LONGTEXT NOT NULL COLLATE {$COLLATE_SORT},
termCorpus LONGTEXT NOT NULL COLLATE {$COLLATE_SORT},
normalCorpus LONGTEXT NOT NULL COLLATE {$COLLATE_SORT}
) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};

View file

@ -0,0 +1,5 @@
CREATE TABLE {$NAMESPACE}_dashboard.dashboard_portal_fngrams (
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
documentID INT UNSIGNED NOT NULL,
ngram CHAR(3) NOT NULL COLLATE {$COLLATE_TEXT}
) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};

View file

@ -0,0 +1,7 @@
CREATE TABLE {$NAMESPACE}_dashboard.dashboard_portal_fngrams_common (
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
ngram CHAR(3) NOT NULL COLLATE {$COLLATE_TEXT},
needsCollection BOOL NOT NULL,
UNIQUE KEY `key_ngram` (ngram),
KEY `key_collect` (needsCollection)
) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};

View file

@ -0,0 +1,81 @@
<?php
// Convert dashboards to a new storage format. The old storage format looks
// like this:
// {
// "0": ["PHID-DSHP-A", ...],
// "1": ["PHID-DSHP-B", ...]
// }
// The new storage format looks like this:
// [
// {
// "panelKey": "abcdefgh",
// "panelPHID": "PHID-DSHP-A",
// "columnKey": "left"
// },
// ...
// ]
// One major issue with the old storage format is that when multiple copies of
// a single dashboard panel appeared on the same dashboard, the UI had a lot
// of difficulty acting on a particular copy because copies were identified
// only by PHID and all copies of the same panel have the same panel PHID.
$dashboard_table = new PhabricatorDashboard();
$conn = $dashboard_table->establishConnection('r');
$table_name = $dashboard_table->getTableName();
$rows = new LiskRawMigrationIterator($conn, $table_name);
foreach ($rows as $row) {
$config = $row['layoutConfig'];
try {
$config = phutil_json_decode($config);
} catch (Exception $ex) {
$config = array();
}
if (!is_array($config)) {
$config = array();
}
$panels = idx($config, 'panelLocations');
if (!is_array($panels)) {
$panels = array();
}
if (idx($config, 'layoutMode') === 'layout-mode-full') {
$column_map = array(
0 => 'main',
);
} else {
$column_map = array(
0 => 'left',
1 => 'right',
);
}
$panel_list = array();
foreach ($panels as $column_idx => $panel_phids) {
$column_key = idx($column_map, $column_idx, 'unknown');
foreach ($panel_phids as $panel_phid) {
$panel_list[] = array(
'panelKey' => Filesystem::readRandomCharacters(8),
'columnKey' => $column_key,
'panelPHID' => $panel_phid,
);
}
}
unset($config['panelLocations']);
$config['panels'] = $panel_list;
queryfx(
$conn,
'UPDATE %R SET layoutConfig = %s WHERE id = %d',
$dashboard_table,
phutil_json_encode($config),
$row['id']);
}

View file

@ -0,0 +1 @@
DROP TABLE IF EXISTS {$NAMESPACE}_dashboard.dashboard_install;

View file

@ -0,0 +1 @@
DROP TABLE IF EXISTS {$NAMESPACE}_dashboard.dashboard_dashboard_ngrams;

View file

@ -0,0 +1 @@
DROP TABLE IF EXISTS {$NAMESPACE}_dashboard.dashboard_dashboardpanel_ngrams;

View file

@ -0,0 +1,9 @@
CREATE TABLE {$NAMESPACE}_dashboard.dashboard_dashboard_fdocument (
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
objectPHID VARBINARY(64) NOT NULL,
isClosed BOOL NOT NULL,
authorPHID VARBINARY(64),
ownerPHID VARBINARY(64),
epochCreated INT UNSIGNED NOT NULL,
epochModified INT UNSIGNED NOT NULL
) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};

View file

@ -0,0 +1,8 @@
CREATE TABLE {$NAMESPACE}_dashboard.dashboard_dashboard_ffield (
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
documentID INT UNSIGNED NOT NULL,
fieldKey VARCHAR(4) NOT NULL COLLATE {$COLLATE_TEXT},
rawCorpus LONGTEXT NOT NULL COLLATE {$COLLATE_SORT},
termCorpus LONGTEXT NOT NULL COLLATE {$COLLATE_SORT},
normalCorpus LONGTEXT NOT NULL COLLATE {$COLLATE_SORT}
) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};

View file

@ -0,0 +1,5 @@
CREATE TABLE {$NAMESPACE}_dashboard.dashboard_dashboard_fngrams (
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
documentID INT UNSIGNED NOT NULL,
ngram CHAR(3) NOT NULL COLLATE {$COLLATE_TEXT}
) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};

View file

@ -0,0 +1,7 @@
CREATE TABLE {$NAMESPACE}_dashboard.dashboard_dashboard_fngrams_common (
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
ngram CHAR(3) NOT NULL COLLATE {$COLLATE_TEXT},
needsCollection BOOL NOT NULL,
UNIQUE KEY `key_ngram` (ngram),
KEY `key_collect` (needsCollection)
) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};

View file

@ -0,0 +1,9 @@
CREATE TABLE {$NAMESPACE}_dashboard.dashboard_panel_fdocument (
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
objectPHID VARBINARY(64) NOT NULL,
isClosed BOOL NOT NULL,
authorPHID VARBINARY(64),
ownerPHID VARBINARY(64),
epochCreated INT UNSIGNED NOT NULL,
epochModified INT UNSIGNED NOT NULL
) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};

View file

@ -0,0 +1,8 @@
CREATE TABLE {$NAMESPACE}_dashboard.dashboard_panel_ffield (
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
documentID INT UNSIGNED NOT NULL,
fieldKey VARCHAR(4) NOT NULL COLLATE {$COLLATE_TEXT},
rawCorpus LONGTEXT NOT NULL COLLATE {$COLLATE_SORT},
termCorpus LONGTEXT NOT NULL COLLATE {$COLLATE_SORT},
normalCorpus LONGTEXT NOT NULL COLLATE {$COLLATE_SORT}
) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};

View file

@ -0,0 +1,5 @@
CREATE TABLE {$NAMESPACE}_dashboard.dashboard_panel_fngrams (
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
documentID INT UNSIGNED NOT NULL,
ngram CHAR(3) NOT NULL COLLATE {$COLLATE_TEXT}
) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};

View file

@ -0,0 +1,7 @@
CREATE TABLE {$NAMESPACE}_dashboard.dashboard_panel_fngrams_common (
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
ngram CHAR(3) NOT NULL COLLATE {$COLLATE_TEXT},
needsCollection BOOL NOT NULL,
UNIQUE KEY `key_ngram` (ngram),
KEY `key_collect` (needsCollection)
) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};

View file

@ -0,0 +1,7 @@
<?php
PhabricatorRebuildIndexesWorker::rebuildObjectsWithQuery(
'PhabricatorDashboardQuery');
PhabricatorRebuildIndexesWorker::rebuildObjectsWithQuery(
'PhabricatorDashboardPanelQuery');

View file

@ -0,0 +1,3 @@
<?php
PhabricatorRebuildIndexesWorker::rebuildObjectsWithQuery('HeraldRuleQuery');

View file

@ -609,6 +609,7 @@ phutil_register_library_map(array(
'DifferentialRevisionIDCommitMessageField' => 'applications/differential/field/DifferentialRevisionIDCommitMessageField.php',
'DifferentialRevisionInlineTransaction' => 'applications/differential/xaction/DifferentialRevisionInlineTransaction.php',
'DifferentialRevisionInlinesController' => 'applications/differential/controller/DifferentialRevisionInlinesController.php',
'DifferentialRevisionJIRAIssueURIsHeraldField' => 'applications/differential/herald/DifferentialRevisionJIRAIssueURIsHeraldField.php',
'DifferentialRevisionListController' => 'applications/differential/controller/DifferentialRevisionListController.php',
'DifferentialRevisionListView' => 'applications/differential/view/DifferentialRevisionListView.php',
'DifferentialRevisionMailReceiver' => 'applications/differential/mail/DifferentialRevisionMailReceiver.php',
@ -2305,12 +2306,14 @@ phutil_register_library_map(array(
'PhabricatorAuthManagementLDAPWorkflow' => 'applications/auth/management/PhabricatorAuthManagementLDAPWorkflow.php',
'PhabricatorAuthManagementListFactorsWorkflow' => 'applications/auth/management/PhabricatorAuthManagementListFactorsWorkflow.php',
'PhabricatorAuthManagementListMFAProvidersWorkflow' => 'applications/auth/management/PhabricatorAuthManagementListMFAProvidersWorkflow.php',
'PhabricatorAuthManagementLockWorkflow' => 'applications/auth/management/PhabricatorAuthManagementLockWorkflow.php',
'PhabricatorAuthManagementRecoverWorkflow' => 'applications/auth/management/PhabricatorAuthManagementRecoverWorkflow.php',
'PhabricatorAuthManagementRefreshWorkflow' => 'applications/auth/management/PhabricatorAuthManagementRefreshWorkflow.php',
'PhabricatorAuthManagementRevokeWorkflow' => 'applications/auth/management/PhabricatorAuthManagementRevokeWorkflow.php',
'PhabricatorAuthManagementStripWorkflow' => 'applications/auth/management/PhabricatorAuthManagementStripWorkflow.php',
'PhabricatorAuthManagementTrustOAuthClientWorkflow' => 'applications/auth/management/PhabricatorAuthManagementTrustOAuthClientWorkflow.php',
'PhabricatorAuthManagementUnlimitWorkflow' => 'applications/auth/management/PhabricatorAuthManagementUnlimitWorkflow.php',
'PhabricatorAuthManagementUnlockWorkflow' => 'applications/auth/management/PhabricatorAuthManagementUnlockWorkflow.php',
'PhabricatorAuthManagementUntrustOAuthClientWorkflow' => 'applications/auth/management/PhabricatorAuthManagementUntrustOAuthClientWorkflow.php',
'PhabricatorAuthManagementVerifyWorkflow' => 'applications/auth/management/PhabricatorAuthManagementVerifyWorkflow.php',
'PhabricatorAuthManagementWorkflow' => 'applications/auth/management/PhabricatorAuthManagementWorkflow.php',
@ -2903,65 +2906,112 @@ phutil_register_library_map(array(
'PhabricatorDarkConsoleTabSetting' => 'applications/settings/setting/PhabricatorDarkConsoleTabSetting.php',
'PhabricatorDarkConsoleVisibleSetting' => 'applications/settings/setting/PhabricatorDarkConsoleVisibleSetting.php',
'PhabricatorDashboard' => 'applications/dashboard/storage/PhabricatorDashboard.php',
'PhabricatorDashboardAddPanelController' => 'applications/dashboard/controller/PhabricatorDashboardAddPanelController.php',
'PhabricatorDashboardAdjustController' => 'applications/dashboard/controller/dashboard/PhabricatorDashboardAdjustController.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',
'PhabricatorDashboardColumn' => 'applications/dashboard/layoutconfig/PhabricatorDashboardColumn.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',
'PhabricatorDashboardEditEngine' => 'applications/dashboard/editor/PhabricatorDashboardEditEngine.php',
'PhabricatorDashboardFavoritesInstallWorkflow' => 'applications/dashboard/install/PhabricatorDashboardFavoritesInstallWorkflow.php',
'PhabricatorDashboardFerretEngine' => 'applications/dashboard/engine/PhabricatorDashboardFerretEngine.php',
'PhabricatorDashboardFullLayoutMode' => 'applications/dashboard/layoutconfig/PhabricatorDashboardFullLayoutMode.php',
'PhabricatorDashboardFulltextEngine' => 'applications/dashboard/engine/PhabricatorDashboardFulltextEngine.php',
'PhabricatorDashboardHalfLayoutMode' => 'applications/dashboard/layoutconfig/PhabricatorDashboardHalfLayoutMode.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',
'PhabricatorDashboardLayoutConfig' => 'applications/dashboard/layoutconfig/PhabricatorDashboardLayoutConfig.php',
'PhabricatorDashboardIconTransaction' => 'applications/dashboard/xaction/dashboard/PhabricatorDashboardIconTransaction.php',
'PhabricatorDashboardInstallController' => 'applications/dashboard/controller/dashboard/PhabricatorDashboardInstallController.php',
'PhabricatorDashboardInstallWorkflow' => 'applications/dashboard/install/PhabricatorDashboardInstallWorkflow.php',
'PhabricatorDashboardLayoutMode' => 'applications/dashboard/layoutconfig/PhabricatorDashboardLayoutMode.php',
'PhabricatorDashboardLayoutTransaction' => 'applications/dashboard/xaction/dashboard/PhabricatorDashboardLayoutTransaction.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',
'PhabricatorDashboardNameTransaction' => 'applications/dashboard/xaction/dashboard/PhabricatorDashboardNameTransaction.php',
'PhabricatorDashboardObjectInstallWorkflow' => 'applications/dashboard/install/PhabricatorDashboardObjectInstallWorkflow.php',
'PhabricatorDashboardOneThirdLayoutMode' => 'applications/dashboard/layoutconfig/PhabricatorDashboardOneThirdLayoutMode.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',
'PhabricatorDashboardPanelContainerIndexEngineExtension' => 'applications/dashboard/engineextension/PhabricatorDashboardPanelContainerIndexEngineExtension.php',
'PhabricatorDashboardPanelContainerInterface' => 'applications/dashboard/interface/PhabricatorDashboardPanelContainerInterface.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',
'PhabricatorDashboardPanelNgrams' => 'applications/dashboard/storage/PhabricatorDashboardPanelNgrams.php',
'PhabricatorDashboardPanelFerretEngine' => 'applications/dashboard/engine/PhabricatorDashboardPanelFerretEngine.php',
'PhabricatorDashboardPanelFulltextEngine' => 'applications/dashboard/engine/PhabricatorDashboardPanelFulltextEngine.php',
'PhabricatorDashboardPanelListController' => 'applications/dashboard/controller/panel/PhabricatorDashboardPanelListController.php',
'PhabricatorDashboardPanelNameTransaction' => 'applications/dashboard/xaction/panel/PhabricatorDashboardPanelNameTransaction.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',
'PhabricatorDashboardPanelRef' => 'applications/dashboard/layoutconfig/PhabricatorDashboardPanelRef.php',
'PhabricatorDashboardPanelRefList' => 'applications/dashboard/layoutconfig/PhabricatorDashboardPanelRefList.php',
'PhabricatorDashboardPanelRenderController' => 'applications/dashboard/controller/panel/PhabricatorDashboardPanelRenderController.php',
'PhabricatorDashboardPanelRenderingEngine' => 'applications/dashboard/engine/PhabricatorDashboardPanelRenderingEngine.php',
'PhabricatorDashboardPanelSearchApplicationCustomField' => 'applications/dashboard/customfield/PhabricatorDashboardPanelSearchApplicationCustomField.php',
'PhabricatorDashboardPanelSearchEngine' => 'applications/dashboard/query/PhabricatorDashboardPanelSearchEngine.php',
'PhabricatorDashboardPanelSearchQueryCustomField' => 'applications/dashboard/customfield/PhabricatorDashboardPanelSearchQueryCustomField.php',
'PhabricatorDashboardPanelTabsCustomField' => 'applications/dashboard/customfield/PhabricatorDashboardPanelTabsCustomField.php',
'PhabricatorDashboardPanelStatusTransaction' => 'applications/dashboard/xaction/panel/PhabricatorDashboardPanelStatusTransaction.php',
'PhabricatorDashboardPanelTabsController' => 'applications/dashboard/controller/panel/PhabricatorDashboardPanelTabsController.php',
'PhabricatorDashboardPanelTransaction' => 'applications/dashboard/storage/PhabricatorDashboardPanelTransaction.php',
'PhabricatorDashboardPanelTransactionEditor' => 'applications/dashboard/editor/PhabricatorDashboardPanelTransactionEditor.php',
'PhabricatorDashboardPanelTransactionQuery' => 'applications/dashboard/query/PhabricatorDashboardPanelTransactionQuery.php',
'PhabricatorDashboardPanelTransactionType' => 'applications/dashboard/xaction/panel/PhabricatorDashboardPanelTransactionType.php',
'PhabricatorDashboardPanelType' => 'applications/dashboard/paneltype/PhabricatorDashboardPanelType.php',
'PhabricatorDashboardPanelViewController' => 'applications/dashboard/controller/PhabricatorDashboardPanelViewController.php',
'PhabricatorDashboardPanelUsedByObjectEdgeType' => 'applications/search/edge/PhabricatorDashboardPanelUsedByObjectEdgeType.php',
'PhabricatorDashboardPanelViewController' => 'applications/dashboard/controller/panel/PhabricatorDashboardPanelViewController.php',
'PhabricatorDashboardPanelsTransaction' => 'applications/dashboard/xaction/dashboard/PhabricatorDashboardPanelsTransaction.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',
'PhabricatorDashboardPortalFerretEngine' => 'applications/dashboard/engine/PhabricatorDashboardPortalFerretEngine.php',
'PhabricatorDashboardPortalFulltextEngine' => 'applications/dashboard/engine/PhabricatorDashboardPortalFulltextEngine.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',
'PhabricatorDashboardPortalPHIDType' => 'applications/dashboard/phid/PhabricatorDashboardPortalPHIDType.php',
'PhabricatorDashboardPortalProfileMenuEngine' => 'applications/dashboard/engine/PhabricatorDashboardPortalProfileMenuEngine.php',
'PhabricatorDashboardPortalQuery' => 'applications/dashboard/query/PhabricatorDashboardPortalQuery.php',
'PhabricatorDashboardPortalSearchConduitAPIMethod' => 'applications/dashboard/conduit/PhabricatorDashboardPortalSearchConduitAPIMethod.php',
'PhabricatorDashboardPortalSearchEngine' => 'applications/dashboard/query/PhabricatorDashboardPortalSearchEngine.php',
'PhabricatorDashboardPortalStatus' => 'applications/dashboard/constants/PhabricatorDashboardPortalStatus.php',
'PhabricatorDashboardPortalTransaction' => 'applications/dashboard/storage/PhabricatorDashboardPortalTransaction.php',
'PhabricatorDashboardPortalTransactionQuery' => 'applications/dashboard/query/PhabricatorDashboardPortalTransactionQuery.php',
'PhabricatorDashboardPortalTransactionType' => 'applications/dashboard/xaction/portal/PhabricatorDashboardPortalTransactionType.php',
'PhabricatorDashboardPortalViewController' => 'applications/dashboard/controller/portal/PhabricatorDashboardPortalViewController.php',
'PhabricatorDashboardProfileController' => 'applications/dashboard/controller/PhabricatorDashboardProfileController.php',
'PhabricatorDashboardProfileMenuItem' => 'applications/search/menuitem/PhabricatorDashboardProfileMenuItem.php',
'PhabricatorDashboardProjectInstallWorkflow' => 'applications/dashboard/install/PhabricatorDashboardProjectInstallWorkflow.php',
'PhabricatorDashboardQuery' => 'applications/dashboard/query/PhabricatorDashboardQuery.php',
'PhabricatorDashboardQueryPanelApplicationEditField' => 'applications/dashboard/editfield/PhabricatorDashboardQueryPanelApplicationEditField.php',
'PhabricatorDashboardQueryPanelApplicationTransaction' => 'applications/dashboard/xaction/panel/PhabricatorDashboardQueryPanelApplicationTransaction.php',
'PhabricatorDashboardQueryPanelInstallController' => 'applications/dashboard/controller/PhabricatorDashboardQueryPanelInstallController.php',
'PhabricatorDashboardQueryPanelQueryEditField' => 'applications/dashboard/editfield/PhabricatorDashboardQueryPanelQueryEditField.php',
'PhabricatorDashboardQueryPanelQueryTransaction' => 'applications/dashboard/xaction/panel/PhabricatorDashboardQueryPanelQueryTransaction.php',
'PhabricatorDashboardQueryPanelType' => 'applications/dashboard/paneltype/PhabricatorDashboardQueryPanelType.php',
'PhabricatorDashboardRemarkupRule' => 'applications/dashboard/remarkup/PhabricatorDashboardRemarkupRule.php',
'PhabricatorDashboardRemovePanelController' => 'applications/dashboard/controller/PhabricatorDashboardRemovePanelController.php',
'PhabricatorDashboardRenderingEngine' => 'applications/dashboard/engine/PhabricatorDashboardRenderingEngine.php',
'PhabricatorDashboardSchemaSpec' => 'applications/dashboard/storage/PhabricatorDashboardSchemaSpec.php',
'PhabricatorDashboardSearchEngine' => 'applications/dashboard/query/PhabricatorDashboardSearchEngine.php',
'PhabricatorDashboardStatusTransaction' => 'applications/dashboard/xaction/dashboard/PhabricatorDashboardStatusTransaction.php',
'PhabricatorDashboardTabsPanelTabsTransaction' => 'applications/dashboard/xaction/panel/PhabricatorDashboardTabsPanelTabsTransaction.php',
'PhabricatorDashboardTabsPanelType' => 'applications/dashboard/paneltype/PhabricatorDashboardTabsPanelType.php',
'PhabricatorDashboardTextPanelTextTransaction' => 'applications/dashboard/xaction/panel/PhabricatorDashboardTextPanelTextTransaction.php',
'PhabricatorDashboardTextPanelType' => 'applications/dashboard/paneltype/PhabricatorDashboardTextPanelType.php',
'PhabricatorDashboardTransaction' => 'applications/dashboard/storage/PhabricatorDashboardTransaction.php',
'PhabricatorDashboardTransactionEditor' => 'applications/dashboard/editor/PhabricatorDashboardTransactionEditor.php',
'PhabricatorDashboardTransactionQuery' => 'applications/dashboard/query/PhabricatorDashboardTransactionQuery.php',
'PhabricatorDashboardViewController' => 'applications/dashboard/controller/PhabricatorDashboardViewController.php',
'PhabricatorDashboardTransactionType' => 'applications/dashboard/xaction/dashboard/PhabricatorDashboardTransactionType.php',
'PhabricatorDashboardTwoThirdsLayoutMode' => 'applications/dashboard/layoutconfig/PhabricatorDashboardTwoThirdsLayoutMode.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',
@ -3028,6 +3078,7 @@ phutil_register_library_map(array(
'PhabricatorEdgeEditType' => 'applications/transactions/edittype/PhabricatorEdgeEditType.php',
'PhabricatorEdgeEditor' => 'infrastructure/edges/editor/PhabricatorEdgeEditor.php',
'PhabricatorEdgeGraph' => 'infrastructure/edges/util/PhabricatorEdgeGraph.php',
'PhabricatorEdgeIndexEngineExtension' => 'applications/search/engineextension/PhabricatorEdgeIndexEngineExtension.php',
'PhabricatorEdgeObject' => 'infrastructure/edges/conduit/PhabricatorEdgeObject.php',
'PhabricatorEdgeObjectQuery' => 'infrastructure/edges/query/PhabricatorEdgeObjectQuery.php',
'PhabricatorEdgeQuery' => 'infrastructure/edges/query/PhabricatorEdgeQuery.php',
@ -3687,6 +3738,7 @@ phutil_register_library_map(array(
'PhabricatorObjectRemarkupRule' => 'infrastructure/markup/rule/PhabricatorObjectRemarkupRule.php',
'PhabricatorObjectSelectorDialog' => 'view/control/PhabricatorObjectSelectorDialog.php',
'PhabricatorObjectStatus' => 'infrastructure/status/PhabricatorObjectStatus.php',
'PhabricatorObjectUsesDashboardPanelEdgeType' => 'applications/search/edge/PhabricatorObjectUsesDashboardPanelEdgeType.php',
'PhabricatorOffsetPagedQuery' => 'infrastructure/query/PhabricatorOffsetPagedQuery.php',
'PhabricatorOldWorldContentSource' => 'infrastructure/contentsource/PhabricatorOldWorldContentSource.php',
'PhabricatorOlderInlinesSetting' => 'applications/settings/setting/PhabricatorOlderInlinesSetting.php',
@ -4031,12 +4083,16 @@ phutil_register_library_map(array(
'PhabricatorProfileMenuEditor' => 'applications/search/editor/PhabricatorProfileMenuEditor.php',
'PhabricatorProfileMenuEngine' => 'applications/search/engine/PhabricatorProfileMenuEngine.php',
'PhabricatorProfileMenuItem' => 'applications/search/menuitem/PhabricatorProfileMenuItem.php',
'PhabricatorProfileMenuItemAffectsObjectEdgeType' => 'applications/search/edge/PhabricatorProfileMenuItemAffectsObjectEdgeType.php',
'PhabricatorProfileMenuItemConfiguration' => 'applications/search/storage/PhabricatorProfileMenuItemConfiguration.php',
'PhabricatorProfileMenuItemConfigurationQuery' => 'applications/search/query/PhabricatorProfileMenuItemConfigurationQuery.php',
'PhabricatorProfileMenuItemConfigurationTransaction' => 'applications/search/storage/PhabricatorProfileMenuItemConfigurationTransaction.php',
'PhabricatorProfileMenuItemConfigurationTransactionQuery' => 'applications/search/query/PhabricatorProfileMenuItemConfigurationTransactionQuery.php',
'PhabricatorProfileMenuItemIconSet' => 'applications/search/menuitem/PhabricatorProfileMenuItemIconSet.php',
'PhabricatorProfileMenuItemIndexEngineExtension' => 'applications/search/engineextension/PhabricatorProfileMenuItemIndexEngineExtension.php',
'PhabricatorProfileMenuItemPHIDType' => 'applications/search/phidtype/PhabricatorProfileMenuItemPHIDType.php',
'PhabricatorProfileMenuItemView' => 'applications/search/engine/PhabricatorProfileMenuItemView.php',
'PhabricatorProfileMenuItemViewList' => 'applications/search/engine/PhabricatorProfileMenuItemViewList.php',
'PhabricatorProject' => 'applications/project/storage/PhabricatorProject.php',
'PhabricatorProjectAddHeraldAction' => 'applications/project/herald/PhabricatorProjectAddHeraldAction.php',
'PhabricatorProjectApplication' => 'applications/project/application/PhabricatorProjectApplication.php',
@ -4174,18 +4230,21 @@ phutil_register_library_map(array(
'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',
'PhabricatorProjectTriggerEditor' => 'applications/project/editor/PhabricatorProjectTriggerEditor.php',
'PhabricatorProjectTriggerInvalidRule' => 'applications/project/trigger/PhabricatorProjectTriggerInvalidRule.php',
'PhabricatorProjectTriggerListController' => 'applications/project/controller/trigger/PhabricatorProjectTriggerListController.php',
'PhabricatorProjectTriggerManiphestOwnerRule' => 'applications/project/trigger/PhabricatorProjectTriggerManiphestOwnerRule.php',
'PhabricatorProjectTriggerManiphestPriorityRule' => 'applications/project/trigger/PhabricatorProjectTriggerManiphestPriorityRule.php',
'PhabricatorProjectTriggerManiphestStatusRule' => 'applications/project/trigger/PhabricatorProjectTriggerManiphestStatusRule.php',
'PhabricatorProjectTriggerNameTransaction' => 'applications/project/xaction/trigger/PhabricatorProjectTriggerNameTransaction.php',
'PhabricatorProjectTriggerPHIDType' => 'applications/project/phid/PhabricatorProjectTriggerPHIDType.php',
'PhabricatorProjectTriggerPlaySoundRule' => 'applications/project/trigger/PhabricatorProjectTriggerPlaySoundRule.php',
'PhabricatorProjectTriggerQuery' => 'applications/project/query/PhabricatorProjectTriggerQuery.php',
'PhabricatorProjectTriggerRemoveProjectsRule' => 'applications/project/trigger/PhabricatorProjectTriggerRemoveProjectsRule.php',
'PhabricatorProjectTriggerRule' => 'applications/project/trigger/PhabricatorProjectTriggerRule.php',
'PhabricatorProjectTriggerRuleRecord' => 'applications/project/trigger/PhabricatorProjectTriggerRuleRecord.php',
'PhabricatorProjectTriggerRulesetTransaction' => 'applications/project/xaction/trigger/PhabricatorProjectTriggerRulesetTransaction.php',
@ -4235,6 +4294,7 @@ phutil_register_library_map(array(
'PhabricatorQueryOrderVector' => 'infrastructure/query/order/PhabricatorQueryOrderVector.php',
'PhabricatorQuickSearchEngineExtension' => 'applications/search/engineextension/PhabricatorQuickSearchEngineExtension.php',
'PhabricatorRateLimitRequestExceptionHandler' => 'aphront/handler/PhabricatorRateLimitRequestExceptionHandler.php',
'PhabricatorRebuildIndexesWorker' => 'applications/search/worker/PhabricatorRebuildIndexesWorker.php',
'PhabricatorRecaptchaConfigOptions' => 'applications/config/option/PhabricatorRecaptchaConfigOptions.php',
'PhabricatorRedirectController' => 'applications/base/controller/PhabricatorRedirectController.php',
'PhabricatorRefreshCSRFController' => 'applications/auth/controller/PhabricatorRefreshCSRFController.php',
@ -6192,6 +6252,7 @@ phutil_register_library_map(array(
'DifferentialRevisionIDCommitMessageField' => 'DifferentialCommitMessageField',
'DifferentialRevisionInlineTransaction' => 'PhabricatorModularTransactionType',
'DifferentialRevisionInlinesController' => 'DifferentialController',
'DifferentialRevisionJIRAIssueURIsHeraldField' => 'DifferentialRevisionHeraldField',
'DifferentialRevisionListController' => 'DifferentialController',
'DifferentialRevisionListView' => 'AphrontView',
'DifferentialRevisionMailReceiver' => 'PhabricatorObjectMailReceiver',
@ -7250,7 +7311,7 @@ phutil_register_library_map(array(
'HeraldRuleEditor' => 'PhabricatorApplicationTransactionEditor',
'HeraldRuleField' => 'HeraldField',
'HeraldRuleFieldGroup' => 'HeraldFieldGroup',
'HeraldRuleIndexEngineExtension' => 'PhabricatorIndexEngineExtension',
'HeraldRuleIndexEngineExtension' => 'PhabricatorEdgeIndexEngineExtension',
'HeraldRuleListController' => 'HeraldController',
'HeraldRuleListView' => 'AphrontView',
'HeraldRuleNameTransaction' => 'HeraldRuleTransactionType',
@ -8134,12 +8195,14 @@ phutil_register_library_map(array(
'PhabricatorAuthManagementLDAPWorkflow' => 'PhabricatorAuthManagementWorkflow',
'PhabricatorAuthManagementListFactorsWorkflow' => 'PhabricatorAuthManagementWorkflow',
'PhabricatorAuthManagementListMFAProvidersWorkflow' => 'PhabricatorAuthManagementWorkflow',
'PhabricatorAuthManagementLockWorkflow' => 'PhabricatorAuthManagementWorkflow',
'PhabricatorAuthManagementRecoverWorkflow' => 'PhabricatorAuthManagementWorkflow',
'PhabricatorAuthManagementRefreshWorkflow' => 'PhabricatorAuthManagementWorkflow',
'PhabricatorAuthManagementRevokeWorkflow' => 'PhabricatorAuthManagementWorkflow',
'PhabricatorAuthManagementStripWorkflow' => 'PhabricatorAuthManagementWorkflow',
'PhabricatorAuthManagementTrustOAuthClientWorkflow' => 'PhabricatorAuthManagementWorkflow',
'PhabricatorAuthManagementUnlimitWorkflow' => 'PhabricatorAuthManagementWorkflow',
'PhabricatorAuthManagementUnlockWorkflow' => 'PhabricatorAuthManagementWorkflow',
'PhabricatorAuthManagementUntrustOAuthClientWorkflow' => 'PhabricatorAuthManagementWorkflow',
'PhabricatorAuthManagementVerifyWorkflow' => 'PhabricatorAuthManagementWorkflow',
'PhabricatorAuthManagementWorkflow' => 'PhabricatorManagementWorkflow',
@ -8840,77 +8903,131 @@ phutil_register_library_map(array(
'PhabricatorFlaggableInterface',
'PhabricatorDestructibleInterface',
'PhabricatorProjectInterface',
'PhabricatorNgramsInterface',
'PhabricatorFulltextInterface',
'PhabricatorFerretInterface',
'PhabricatorDashboardPanelContainerInterface',
),
'PhabricatorDashboardAddPanelController' => 'PhabricatorDashboardController',
'PhabricatorDashboardAdjustController' => 'PhabricatorDashboardController',
'PhabricatorDashboardApplication' => 'PhabricatorApplication',
'PhabricatorDashboardApplicationInstallWorkflow' => 'PhabricatorDashboardInstallWorkflow',
'PhabricatorDashboardArchiveController' => 'PhabricatorDashboardController',
'PhabricatorDashboardArrangeController' => 'PhabricatorDashboardProfileController',
'PhabricatorDashboardColumn' => 'Phobject',
'PhabricatorDashboardConsoleController' => 'PhabricatorDashboardController',
'PhabricatorDashboardController' => 'PhabricatorController',
'PhabricatorDashboardDAO' => 'PhabricatorLiskDAO',
'PhabricatorDashboardDashboardHasPanelEdgeType' => 'PhabricatorEdgeType',
'PhabricatorDashboardDashboardPHIDType' => 'PhabricatorPHIDType',
'PhabricatorDashboardDatasource' => 'PhabricatorTypeaheadDatasource',
'PhabricatorDashboardEditController' => 'PhabricatorDashboardController',
'PhabricatorDashboardEditEngine' => 'PhabricatorEditEngine',
'PhabricatorDashboardFavoritesInstallWorkflow' => 'PhabricatorDashboardApplicationInstallWorkflow',
'PhabricatorDashboardFerretEngine' => 'PhabricatorFerretEngine',
'PhabricatorDashboardFullLayoutMode' => 'PhabricatorDashboardLayoutMode',
'PhabricatorDashboardFulltextEngine' => 'PhabricatorFulltextEngine',
'PhabricatorDashboardHalfLayoutMode' => 'PhabricatorDashboardLayoutMode',
'PhabricatorDashboardHomeInstallWorkflow' => 'PhabricatorDashboardApplicationInstallWorkflow',
'PhabricatorDashboardIconSet' => 'PhabricatorIconSet',
'PhabricatorDashboardInstall' => 'PhabricatorDashboardDAO',
'PhabricatorDashboardIconTransaction' => 'PhabricatorDashboardTransactionType',
'PhabricatorDashboardInstallController' => 'PhabricatorDashboardController',
'PhabricatorDashboardLayoutConfig' => 'Phobject',
'PhabricatorDashboardInstallWorkflow' => 'Phobject',
'PhabricatorDashboardLayoutMode' => 'Phobject',
'PhabricatorDashboardLayoutTransaction' => 'PhabricatorDashboardTransactionType',
'PhabricatorDashboardListController' => 'PhabricatorDashboardController',
'PhabricatorDashboardManageController' => 'PhabricatorDashboardProfileController',
'PhabricatorDashboardMovePanelController' => 'PhabricatorDashboardController',
'PhabricatorDashboardNgrams' => 'PhabricatorSearchNgrams',
'PhabricatorDashboardNameTransaction' => 'PhabricatorDashboardTransactionType',
'PhabricatorDashboardObjectInstallWorkflow' => 'PhabricatorDashboardInstallWorkflow',
'PhabricatorDashboardOneThirdLayoutMode' => 'PhabricatorDashboardLayoutMode',
'PhabricatorDashboardPanel' => array(
'PhabricatorDashboardDAO',
'PhabricatorApplicationTransactionInterface',
'PhabricatorPolicyInterface',
'PhabricatorCustomFieldInterface',
'PhabricatorFlaggableInterface',
'PhabricatorDestructibleInterface',
'PhabricatorNgramsInterface',
'PhabricatorFulltextInterface',
'PhabricatorFerretInterface',
'PhabricatorDashboardPanelContainerInterface',
),
'PhabricatorDashboardPanelArchiveController' => 'PhabricatorDashboardController',
'PhabricatorDashboardPanelCoreCustomField' => array(
'PhabricatorDashboardPanelCustomField',
'PhabricatorStandardCustomFieldInterface',
),
'PhabricatorDashboardPanelCustomField' => 'PhabricatorCustomField',
'PhabricatorDashboardPanelContainerIndexEngineExtension' => 'PhabricatorEdgeIndexEngineExtension',
'PhabricatorDashboardPanelDatasource' => 'PhabricatorTypeaheadDatasource',
'PhabricatorDashboardPanelEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod',
'PhabricatorDashboardPanelEditController' => 'PhabricatorDashboardController',
'PhabricatorDashboardPanelEditEngine' => 'PhabricatorEditEngine',
'PhabricatorDashboardPanelEditproController' => 'PhabricatorDashboardController',
'PhabricatorDashboardPanelHasDashboardEdgeType' => 'PhabricatorEdgeType',
'PhabricatorDashboardPanelFerretEngine' => 'PhabricatorFerretEngine',
'PhabricatorDashboardPanelFulltextEngine' => 'PhabricatorFulltextEngine',
'PhabricatorDashboardPanelListController' => 'PhabricatorDashboardController',
'PhabricatorDashboardPanelNgrams' => 'PhabricatorSearchNgrams',
'PhabricatorDashboardPanelNameTransaction' => 'PhabricatorDashboardPanelTransactionType',
'PhabricatorDashboardPanelPHIDType' => 'PhabricatorPHIDType',
'PhabricatorDashboardPanelPropertyTransaction' => 'PhabricatorDashboardPanelTransactionType',
'PhabricatorDashboardPanelQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorDashboardPanelRef' => 'Phobject',
'PhabricatorDashboardPanelRefList' => 'Phobject',
'PhabricatorDashboardPanelRenderController' => 'PhabricatorDashboardController',
'PhabricatorDashboardPanelRenderingEngine' => 'Phobject',
'PhabricatorDashboardPanelSearchApplicationCustomField' => 'PhabricatorStandardCustomField',
'PhabricatorDashboardPanelSearchEngine' => 'PhabricatorApplicationSearchEngine',
'PhabricatorDashboardPanelSearchQueryCustomField' => 'PhabricatorStandardCustomField',
'PhabricatorDashboardPanelTabsCustomField' => 'PhabricatorStandardCustomField',
'PhabricatorDashboardPanelTransaction' => 'PhabricatorApplicationTransaction',
'PhabricatorDashboardPanelStatusTransaction' => 'PhabricatorDashboardPanelTransactionType',
'PhabricatorDashboardPanelTabsController' => 'PhabricatorDashboardController',
'PhabricatorDashboardPanelTransaction' => 'PhabricatorModularTransaction',
'PhabricatorDashboardPanelTransactionEditor' => 'PhabricatorApplicationTransactionEditor',
'PhabricatorDashboardPanelTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
'PhabricatorDashboardPanelTransactionType' => 'PhabricatorModularTransactionType',
'PhabricatorDashboardPanelType' => 'Phobject',
'PhabricatorDashboardPanelUsedByObjectEdgeType' => 'PhabricatorEdgeType',
'PhabricatorDashboardPanelViewController' => 'PhabricatorDashboardController',
'PhabricatorDashboardPanelsTransaction' => 'PhabricatorDashboardTransactionType',
'PhabricatorDashboardPortal' => array(
'PhabricatorDashboardDAO',
'PhabricatorApplicationTransactionInterface',
'PhabricatorPolicyInterface',
'PhabricatorDestructibleInterface',
'PhabricatorProjectInterface',
'PhabricatorFulltextInterface',
'PhabricatorFerretInterface',
),
'PhabricatorDashboardPortalController' => 'PhabricatorDashboardController',
'PhabricatorDashboardPortalDatasource' => 'PhabricatorTypeaheadDatasource',
'PhabricatorDashboardPortalEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod',
'PhabricatorDashboardPortalEditController' => 'PhabricatorDashboardPortalController',
'PhabricatorDashboardPortalEditEngine' => 'PhabricatorEditEngine',
'PhabricatorDashboardPortalEditor' => 'PhabricatorApplicationTransactionEditor',
'PhabricatorDashboardPortalFerretEngine' => 'PhabricatorFerretEngine',
'PhabricatorDashboardPortalFulltextEngine' => 'PhabricatorFulltextEngine',
'PhabricatorDashboardPortalInstallWorkflow' => 'PhabricatorDashboardObjectInstallWorkflow',
'PhabricatorDashboardPortalListController' => 'PhabricatorDashboardPortalController',
'PhabricatorDashboardPortalMenuItem' => 'PhabricatorProfileMenuItem',
'PhabricatorDashboardPortalNameTransaction' => 'PhabricatorDashboardPortalTransactionType',
'PhabricatorDashboardPortalPHIDType' => 'PhabricatorPHIDType',
'PhabricatorDashboardPortalProfileMenuEngine' => 'PhabricatorProfileMenuEngine',
'PhabricatorDashboardPortalQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorDashboardPortalSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod',
'PhabricatorDashboardPortalSearchEngine' => 'PhabricatorApplicationSearchEngine',
'PhabricatorDashboardPortalStatus' => 'Phobject',
'PhabricatorDashboardPortalTransaction' => 'PhabricatorModularTransaction',
'PhabricatorDashboardPortalTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
'PhabricatorDashboardPortalTransactionType' => 'PhabricatorModularTransactionType',
'PhabricatorDashboardPortalViewController' => 'PhabricatorDashboardPortalController',
'PhabricatorDashboardProfileController' => 'PhabricatorController',
'PhabricatorDashboardProfileMenuItem' => 'PhabricatorProfileMenuItem',
'PhabricatorDashboardProjectInstallWorkflow' => 'PhabricatorDashboardObjectInstallWorkflow',
'PhabricatorDashboardQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorDashboardQueryPanelApplicationEditField' => 'PhabricatorEditField',
'PhabricatorDashboardQueryPanelApplicationTransaction' => 'PhabricatorDashboardPanelPropertyTransaction',
'PhabricatorDashboardQueryPanelInstallController' => 'PhabricatorDashboardController',
'PhabricatorDashboardQueryPanelQueryEditField' => 'PhabricatorEditField',
'PhabricatorDashboardQueryPanelQueryTransaction' => 'PhabricatorDashboardPanelPropertyTransaction',
'PhabricatorDashboardQueryPanelType' => 'PhabricatorDashboardPanelType',
'PhabricatorDashboardRemarkupRule' => 'PhabricatorObjectRemarkupRule',
'PhabricatorDashboardRemovePanelController' => 'PhabricatorDashboardController',
'PhabricatorDashboardRenderingEngine' => 'Phobject',
'PhabricatorDashboardSchemaSpec' => 'PhabricatorConfigSchemaSpec',
'PhabricatorDashboardSearchEngine' => 'PhabricatorApplicationSearchEngine',
'PhabricatorDashboardStatusTransaction' => 'PhabricatorDashboardTransactionType',
'PhabricatorDashboardTabsPanelTabsTransaction' => 'PhabricatorDashboardPanelPropertyTransaction',
'PhabricatorDashboardTabsPanelType' => 'PhabricatorDashboardPanelType',
'PhabricatorDashboardTextPanelTextTransaction' => 'PhabricatorDashboardPanelPropertyTransaction',
'PhabricatorDashboardTextPanelType' => 'PhabricatorDashboardPanelType',
'PhabricatorDashboardTransaction' => 'PhabricatorApplicationTransaction',
'PhabricatorDashboardTransaction' => 'PhabricatorModularTransaction',
'PhabricatorDashboardTransactionEditor' => 'PhabricatorApplicationTransactionEditor',
'PhabricatorDashboardTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
'PhabricatorDashboardTransactionType' => 'PhabricatorModularTransactionType',
'PhabricatorDashboardTwoThirdsLayoutMode' => 'PhabricatorDashboardLayoutMode',
'PhabricatorDashboardViewController' => 'PhabricatorDashboardProfileController',
'PhabricatorDataCacheSpec' => 'PhabricatorCacheSpec',
'PhabricatorDataNotAttachedException' => 'Exception',
@ -8975,6 +9092,7 @@ phutil_register_library_map(array(
'PhabricatorEdgeEditType' => 'PhabricatorPHIDListEditType',
'PhabricatorEdgeEditor' => 'Phobject',
'PhabricatorEdgeGraph' => 'AbstractDirectedGraph',
'PhabricatorEdgeIndexEngineExtension' => 'PhabricatorIndexEngineExtension',
'PhabricatorEdgeObject' => array(
'Phobject',
'PhabricatorPolicyInterface',
@ -9714,6 +9832,7 @@ phutil_register_library_map(array(
'PhabricatorObjectRemarkupRule' => 'PhutilRemarkupRule',
'PhabricatorObjectSelectorDialog' => 'Phobject',
'PhabricatorObjectStatus' => 'Phobject',
'PhabricatorObjectUsesDashboardPanelEdgeType' => 'PhabricatorEdgeType',
'PhabricatorOffsetPagedQuery' => 'PhabricatorQuery',
'PhabricatorOldWorldContentSource' => 'PhabricatorContentSource',
'PhabricatorOlderInlinesSetting' => 'PhabricatorSelectSetting',
@ -10130,17 +10249,22 @@ phutil_register_library_map(array(
'PhabricatorProfileMenuEditor' => 'PhabricatorApplicationTransactionEditor',
'PhabricatorProfileMenuEngine' => 'Phobject',
'PhabricatorProfileMenuItem' => 'Phobject',
'PhabricatorProfileMenuItemAffectsObjectEdgeType' => 'PhabricatorEdgeType',
'PhabricatorProfileMenuItemConfiguration' => array(
'PhabricatorSearchDAO',
'PhabricatorPolicyInterface',
'PhabricatorExtendedPolicyInterface',
'PhabricatorApplicationTransactionInterface',
'PhabricatorIndexableInterface',
),
'PhabricatorProfileMenuItemConfigurationQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorProfileMenuItemConfigurationTransaction' => 'PhabricatorApplicationTransaction',
'PhabricatorProfileMenuItemConfigurationTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
'PhabricatorProfileMenuItemIconSet' => 'PhabricatorIconSet',
'PhabricatorProfileMenuItemIndexEngineExtension' => 'PhabricatorEdgeIndexEngineExtension',
'PhabricatorProfileMenuItemPHIDType' => 'PhabricatorPHIDType',
'PhabricatorProfileMenuItemView' => 'Phobject',
'PhabricatorProfileMenuItemViewList' => 'Phobject',
'PhabricatorProject' => array(
'PhabricatorProjectDAO',
'PhabricatorApplicationTransactionInterface',
@ -10313,18 +10437,21 @@ phutil_register_library_map(array(
'PhabricatorIndexableInterface',
'PhabricatorDestructibleInterface',
),
'PhabricatorProjectTriggerAddProjectsRule' => 'PhabricatorProjectTriggerRule',
'PhabricatorProjectTriggerController' => 'PhabricatorProjectController',
'PhabricatorProjectTriggerCorruptionException' => 'Exception',
'PhabricatorProjectTriggerEditController' => 'PhabricatorProjectTriggerController',
'PhabricatorProjectTriggerEditor' => 'PhabricatorApplicationTransactionEditor',
'PhabricatorProjectTriggerInvalidRule' => 'PhabricatorProjectTriggerRule',
'PhabricatorProjectTriggerListController' => 'PhabricatorProjectTriggerController',
'PhabricatorProjectTriggerManiphestOwnerRule' => 'PhabricatorProjectTriggerRule',
'PhabricatorProjectTriggerManiphestPriorityRule' => 'PhabricatorProjectTriggerRule',
'PhabricatorProjectTriggerManiphestStatusRule' => 'PhabricatorProjectTriggerRule',
'PhabricatorProjectTriggerNameTransaction' => 'PhabricatorProjectTriggerTransactionType',
'PhabricatorProjectTriggerPHIDType' => 'PhabricatorPHIDType',
'PhabricatorProjectTriggerPlaySoundRule' => 'PhabricatorProjectTriggerRule',
'PhabricatorProjectTriggerQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorProjectTriggerRemoveProjectsRule' => 'PhabricatorProjectTriggerRule',
'PhabricatorProjectTriggerRule' => 'Phobject',
'PhabricatorProjectTriggerRuleRecord' => 'Phobject',
'PhabricatorProjectTriggerRulesetTransaction' => 'PhabricatorProjectTriggerTransactionType',
@ -10377,6 +10504,7 @@ phutil_register_library_map(array(
),
'PhabricatorQuickSearchEngineExtension' => 'PhabricatorDatasourceEngineExtension',
'PhabricatorRateLimitRequestExceptionHandler' => 'PhabricatorRequestExceptionHandler',
'PhabricatorRebuildIndexesWorker' => 'PhabricatorWorker',
'PhabricatorRecaptchaConfigOptions' => 'PhabricatorApplicationConfigOptions',
'PhabricatorRedirectController' => 'PhabricatorController',
'PhabricatorRefreshCSRFController' => 'PhabricatorAuthController',

View file

@ -13,6 +13,7 @@ final class PhabricatorAuthListController
$list = new PHUIObjectItemListView();
$can_manage = $this->hasApplicationCapability(
AuthManageProvidersCapability::CAPABILITY);
$is_locked = PhabricatorEnv::getEnvConfig('auth.lock-config');
foreach ($configs as $config) {
$item = new PHUIObjectItemView();
@ -69,7 +70,8 @@ final class PhabricatorAuthListController
$crumbs->addTextCrumb(pht('Login and Registration'));
$crumbs->setBorder(true);
$guidance_context = new PhabricatorAuthProvidersGuidanceContext();
$guidance_context = id(new PhabricatorAuthProvidersGuidanceContext())
->setCanManage($can_manage);
$guidance = id(new PhabricatorGuidanceEngine())
->setViewer($viewer)
@ -81,7 +83,7 @@ final class PhabricatorAuthListController
->setButtonType(PHUIButtonView::BUTTONTYPE_SIMPLE)
->setHref($this->getApplicationURI('config/new/'))
->setIcon('fa-plus')
->setDisabled(!$can_manage)
->setDisabled(!$can_manage || $is_locked)
->setText(pht('Add Provider'));
$list->setFlush(true);

View file

@ -389,7 +389,7 @@ final class PhabricatorAuthSessionEngine extends Phobject {
* appropriate for one-time checks.
*
* @param PhabricatorUser User whose session needs to be in high security.
* @param AphrontReqeust Current request.
* @param AphrontRequest Current request.
* @param string URI to return the user to if they cancel.
* @return PhabricatorAuthHighSecurityToken Security token.
* @task hisec
@ -421,7 +421,7 @@ final class PhabricatorAuthSessionEngine extends Phobject {
* use @{method:requireHighSecurityToken}.
*
* @param PhabricatorUser User whose session needs to be in high security.
* @param AphrontReqeust Current request.
* @param AphrontRequest Current request.
* @param string URI to return the user to if they cancel.
* @param bool True to jump partial sessions directly into high
* security instead of just upgrading them to full

View file

@ -1,4 +1,17 @@
<?php
final class PhabricatorAuthProvidersGuidanceContext
extends PhabricatorGuidanceContext {}
extends PhabricatorGuidanceContext {
private $canManage = false;
public function setCanManage($can_manage) {
$this->canManage = $can_manage;
return $this;
}
public function getCanManage() {
return $this->canManage;
}
}

View file

@ -92,6 +92,25 @@ final class PhabricatorAuthProvidersGuidanceEngineExtension
->setMessage($message);
}
$locked_config_key = 'auth.lock-config';
$is_locked = PhabricatorEnv::getEnvConfig($locked_config_key);
if ($is_locked) {
$message = pht(
'Authentication provider configuration is locked, and can not be '.
'changed without being unlocked. See the configuration setting %s '.
'for details.',
phutil_tag(
'a',
array(
'href' => '/config/edit/'.$locked_config_key,
),
$locked_config_key));
$results[] = $this->newWarning('auth.locked-config')
->setPriority(500)
->setMessage($message);
}
return $results;
}

View file

@ -0,0 +1,32 @@
<?php
final class PhabricatorAuthManagementLockWorkflow
extends PhabricatorAuthManagementWorkflow {
protected function didConstruct() {
$this
->setName('lock')
->setExamples('**lock**')
->setSynopsis(
pht(
'Lock authentication provider config, to prevent changes to '.
'the config without doing **bin/auth unlock**.'));
}
public function execute(PhutilArgumentParser $args) {
$console = PhutilConsole::getConsole();
$key = 'auth.lock-config';
$config_entry = PhabricatorConfigEntry::loadConfigEntry($key);
$config_entry->setValue(true);
// If the entry has been deleted, resurrect it.
$config_entry->setIsDeleted(0);
$config_entry->save();
echo tsprintf(
"%s\n",
pht('Locked the authentication provider configuration.'));
}
}

View file

@ -0,0 +1,33 @@
<?php
final class PhabricatorAuthManagementUnlockWorkflow
extends PhabricatorAuthManagementWorkflow {
protected function didConstruct() {
$this
->setName('unlock')
->setExamples('**unlock**')
->setSynopsis(
pht(
'Unlock the authentication provider config, to make it possible '.
'to edit the config using the web UI. Make sure to do '.
'**bin/auth lock** when done editing the configuration.'));
}
public function execute(PhutilArgumentParser $args) {
$console = PhutilConsole::getConsole();
$key = 'auth.lock-config';
$config_entry = PhabricatorConfigEntry::loadConfigEntry($key);
$config_entry->setValue(false);
// If the entry has been deleted, resurrect it.
$config_entry->setIsDeleted(0);
$config_entry->save();
echo tsprintf(
"%s\n",
pht('Unlocked the authentication provider configuration.'));
}
}

View file

@ -238,6 +238,7 @@ final class CelerityDefaultPostprocessor
'grey.button.gradient' => 'linear-gradient(to bottom, #ffffff, #f1f0f1)',
'grey.button.hover' => 'linear-gradient(to bottom, #ffffff, #eeebec)',
'document.border' => '#dedee1',
);
}

View file

@ -22,6 +22,7 @@ final class PhabricatorAuthSetupCheck extends PhabricatorSetupCheck {
->setViewer(PhabricatorUser::getOmnipotentUser())
->execute();
$did_warn = false;
if (!$configs) {
$message = pht(
'You have not configured any authentication providers yet. You '.
@ -35,6 +36,42 @@ final class PhabricatorAuthSetupCheck extends PhabricatorSetupCheck {
->setName(pht('No Authentication Providers Configured'))
->setMessage($message)
->addLink('/auth/', pht('Auth Application'));
$did_warn = true;
}
// This check is meant for new administrators, but we don't want to
// show both this warning and the "No Auth Providers" warning. Also,
// show this as a reminder to go back and do a `bin/auth lock` after
// they make their desired changes.
$is_locked = PhabricatorEnv::getEnvConfig('auth.lock-config');
if (!$is_locked && !$did_warn) {
$message = pht(
'Your authentication provider configuration is unlocked. Once you '.
'finish setting up or modifying authentication, you should lock the '.
'configuration to prevent unauthorized changes.'.
"\n\n".
'Leaving your authentication provider configuration unlocked '.
'increases the damage that a compromised administrator account can '.
'do to your install, by, for example, changing the authentication '.
'provider to a server they control and intercepting usernames and '.
'passwords.'.
"\n\n".
'To prevent this attack, you should configure your authentication '.
'providers, and then lock the configuration by doing `%s` '.
'from the command line. This will prevent changing the '.
'authentication provider config without first doing `%s`.',
'bin/auth lock',
'bin/auth unlock');
$this
->newIssue('auth.config-unlocked')
->setShortName(pht('Auth Config Unlocked'))
->setName(pht('Authenticaton Provider Configuration Unlocked'))
->setMessage($message)
->addRelatedPhabricatorConfig('auth.lock-config')
->addCommand(
hsprintf(
'<tt>phabricator/ $</tt> ./bin/auth lock'));
}
}
}

View file

@ -73,6 +73,26 @@ final class PhabricatorAuthenticationConfigOptions
->addExample(
"yourcompany.com\nmail.yourcompany.com",
pht('Valid Setting')),
$this->newOption('auth.lock-config', 'bool', false)
->setBoolOptions(
array(
pht('Auth provider config must be unlocked before editing'),
pht('Auth provider config can be edited without unlocking'),
))
->setSummary(
pht(
'Require administrators to unlock the authentication provider '.
'configuration from the CLI before it can be edited.'))
->setDescription(
pht(
'When set to `true`, the authentication provider configuration '.
'for this instance can not be modified without first running '.
'`bin/auth unlock` from the command line. This is to reduce '.
'the security impact of a compromised administrator account. '.
"\n\n".
'After running `bin/auth unlock` and making your changes to the '.
'authentication provider config, you should run `bin/auth lock`.'))
->setLocked(true),
$this->newOption('account.editable', 'bool', true)
->setBoolOptions(
array(

View file

@ -163,14 +163,26 @@ EOTEXT
'mailto' => true,
))
->setSummary(
pht('Determines which URI protocols are auto-linked.'))
pht(
'Determines which URI protocols are valid for links and '.
'redirects.'))
->setDescription(
pht(
"When users write comments which have URIs, they'll be ".
"automatically linked if the protocol appears in this set. This ".
"whitelist is primarily to prevent security issues like ".
"%s URIs.",
'javascript://'))
'When users write comments which have URIs, they will be '.
'automatically turned into clickable links if the URI protocol '.
'appears in this set.'.
"\n\n".
'This set of allowed protocols is primarily intended to prevent '.
'security issues with "javascript:" and other potentially '.
'dangerous URI handlers.'.
"\n\n".
'This set is also used to enforce valid redirect URIs. '.
'Phabricator will refuse to issue a HTTP "Location" redirect to a '.
'URI with a protocol not on this set.'.
"\n\n".
'Usually, "http" and "https" should be present in this set. If '.
'you remove one or both protocols, some Phabricator features '.
'which rely on links or redirects may not work.'))
->addExample("http\nhttps", pht('Valid Setting'))
->setLocked(true),
$this->newOption(

View file

@ -136,7 +136,7 @@ final class ConpherenceThreadQuery
protected function buildGroupClause(AphrontDatabaseConnection $conn_r) {
if ($this->participantPHIDs !== null || strlen($this->fulltext)) {
return 'GROUP BY thread.id';
return qsprintf($conn_r, 'GROUP BY thread.id');
} else {
return $this->buildApplicationSearchGroupClause($conn_r);
}
@ -192,18 +192,24 @@ final class ConpherenceThreadQuery
if ($can_optimize) {
$members_policy = id(new ConpherenceThreadMembersPolicyRule())
->getObjectPolicyFullKey();
$policies = array(
$members_policy,
PhabricatorPolicies::POLICY_USER,
PhabricatorPolicies::POLICY_ADMIN,
PhabricatorPolicies::POLICY_NOONE,
);
if ($viewer->isLoggedIn()) {
$where[] = qsprintf(
$conn,
'thread.viewPolicy != %s OR vp.participantPHID = %s',
$members_policy,
'thread.viewPolicy NOT IN (%Ls) OR vp.participantPHID = %s',
$policies,
$viewer->getPHID());
} else {
$where[] = qsprintf(
$conn,
'thread.viewPolicy != %s',
$members_policy);
'thread.viewPolicy NOT IN (%Ls)',
$policies);
}
}

View file

@ -224,12 +224,12 @@ final class ConpherenceLayoutView extends AphrontTagView {
private function buildNUXView() {
$viewer = $this->getViewer();
$engine = new ConpherenceThreadSearchEngine();
$engine->setViewer($viewer);
$engine = id(new ConpherenceThreadSearchEngine())
->setViewer($viewer);
$saved = $engine->buildSavedQueryFromBuiltin('all');
$query = $engine->buildQueryFromSavedQuery($saved);
$pager = $engine->newPagerForSavedQuery($saved);
$pager->setPageSize(10);
$pager = $engine->newPagerForSavedQuery($saved)
->setPageSize(10);
$results = $engine->executeQuery($query, $pager);
$view = $engine->renderResults($results, $saved);

View file

@ -10,6 +10,10 @@ final class PhabricatorDashboardApplication extends PhabricatorApplication {
return '/dashboard/';
}
public function getTypeaheadURI() {
return '/dashboard/console/';
}
public function getShortDescription() {
return pht('Create Custom Pages');
}
@ -27,6 +31,9 @@ final class PhabricatorDashboardApplication extends PhabricatorApplication {
}
public function getRoutes() {
$menu_rules = $this->getProfileMenuRouting(
'PhabricatorDashboardPortalViewController');
return array(
'/W(?P<id>\d+)' => 'PhabricatorDashboardPanelViewController',
'/dashboard/' => array(
@ -34,29 +41,39 @@ final class PhabricatorDashboardApplication extends PhabricatorApplication {
=> 'PhabricatorDashboardListController',
'view/(?P<id>\d+)/' => 'PhabricatorDashboardViewController',
'archive/(?P<id>\d+)/' => 'PhabricatorDashboardArchiveController',
'manage/(?P<id>\d+)/' => 'PhabricatorDashboardManageController',
'arrange/(?P<id>\d+)/' => 'PhabricatorDashboardArrangeController',
'create/' => 'PhabricatorDashboardEditController',
'edit/(?:(?P<id>\d+)/)?' => 'PhabricatorDashboardEditController',
'install/(?:(?P<id>\d+)/)?' => 'PhabricatorDashboardInstallController',
'addpanel/(?P<id>\d+)/' => 'PhabricatorDashboardAddPanelController',
'movepanel/(?P<id>\d+)/' => 'PhabricatorDashboardMovePanelController',
'removepanel/(?P<id>\d+)/'
=> 'PhabricatorDashboardRemovePanelController',
$this->getEditRoutePattern('edit/') =>
'PhabricatorDashboardEditController',
'install/(?P<id>\d+)/'.
'(?:(?P<workflowKey>[^/]+)/'.
'(?:(?P<modeKey>[^/]+)/)?)?' =>
'PhabricatorDashboardInstallController',
'console/' => 'PhabricatorDashboardConsoleController',
'adjust/(?P<op>remove|add|move)/'
=> 'PhabricatorDashboardAdjustController',
'panel/' => array(
'install/(?P<engineKey>[^/]+)/(?:(?P<queryKey>[^/]+)/)?' =>
'PhabricatorDashboardQueryPanelInstallController',
'(?:query/(?P<queryKey>[^/]+)/)?'
=> 'PhabricatorDashboardPanelListController',
'create/' => 'PhabricatorDashboardPanelEditController',
$this->getEditRoutePattern('editpro/')
=> 'PhabricatorDashboardPanelEditproController',
'edit/(?:(?P<id>\d+)/)?' => 'PhabricatorDashboardPanelEditController',
$this->getEditRoutePattern('edit/')
=> 'PhabricatorDashboardPanelEditController',
'render/(?P<id>\d+)/' => 'PhabricatorDashboardPanelRenderController',
'archive/(?P<id>\d+)/'
=> 'PhabricatorDashboardPanelArchiveController',
'tabs/(?P<id>\d+)/(?P<op>add|move|remove|rename)/'
=> 'PhabricatorDashboardPanelTabsController',
),
),
'/portal/' => array(
$this->getQueryRoutePattern() =>
'PhabricatorDashboardPortalListController',
$this->getEditRoutePattern('edit/') =>
'PhabricatorDashboardPortalEditController',
'view/(?P<portalID>\d)/' => array(
'' => 'PhabricatorDashboardPortalViewController',
) + $menu_rules,
),
);
}

View file

@ -0,0 +1,19 @@
<?php
final class PhabricatorDashboardPortalEditConduitAPIMethod
extends PhabricatorEditEngineAPIMethod {
public function getAPIMethodName() {
return 'portal.edit';
}
public function newEditEngine() {
return new PhabricatorDashboardPortalEditEngine();
}
public function getMethodSummary() {
return pht(
'Apply transactions to create a new portal or edit an existing one.');
}
}

View file

@ -0,0 +1,18 @@
<?php
final class PhabricatorDashboardPortalSearchConduitAPIMethod
extends PhabricatorSearchEngineAPIMethod {
public function getAPIMethodName() {
return 'portal.search';
}
public function newSearchEngine() {
return new PhabricatorDashboardPortalSearchEngine();
}
public function getMethodSummary() {
return pht('Read information about portals.');
}
}

View file

@ -0,0 +1,9 @@
<?php
final class PhabricatorDashboardPortalStatus
extends Phobject {
const STATUS_ACTIVE = 'active';
const STATUS_ARCHIVED = 'archived';
}

View file

@ -1,104 +0,0 @@
<?php
final class PhabricatorDashboardAddPanelController
extends PhabricatorDashboardController {
public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer();
$id = $request->getURIData('id');
$dashboard = id(new PhabricatorDashboardQuery())
->setViewer($viewer)
->withIDs(array($id))
->needPanels(true)
->requireCapabilities(
array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT,
))
->executeOne();
if (!$dashboard) {
return new Aphront404Response();
}
$redirect_uri = $this->getApplicationURI(
'arrange/'.$dashboard->getID().'/');
$v_panel = head($request->getArr('panel'));
$e_panel = true;
$errors = array();
if ($request->isFormPost()) {
if (strlen($v_panel)) {
$panel = id(new PhabricatorDashboardPanelQuery())
->setViewer($viewer)
->withIDs(array($v_panel))
->executeOne();
if (!$panel) {
$errors[] = pht('Not a valid panel.');
$e_panel = pht('Invalid');
}
$on_dashboard = $dashboard->getPanels();
$on_ids = mpull($on_dashboard, null, 'getID');
if (array_key_exists($v_panel, $on_ids)) {
$p_name = $panel->getName();
$errors[] = pht('Panel "%s" already exists on dashboard.', $p_name);
$e_panel = pht('Invalid');
}
} else {
$errors[] = pht('Select a panel to add.');
$e_panel = pht('Required');
}
if (!$errors) {
PhabricatorDashboardTransactionEditor::addPanelToDashboard(
$viewer,
PhabricatorContentSource::newFromRequest($request),
$panel,
$dashboard,
$request->getInt('column', 0));
return id(new AphrontRedirectResponse())->setURI($redirect_uri);
}
}
$panels = id(new PhabricatorDashboardPanelQuery())
->setViewer($viewer)
->withArchived(false)
->execute();
if (!$panels) {
return $this->newDialog()
->setTitle(pht('No Panels Exist Yet'))
->appendParagraph(
pht(
'You have not created any dashboard panels yet, so you can not '.
'add an existing panel.'))
->appendParagraph(
pht('Instead, add a new panel.'))
->addCancelButton($redirect_uri);
}
$form = id(new AphrontFormView())
->setUser($viewer)
->addHiddenInput('column', $request->getInt('column'))
->appendRemarkupInstructions(
pht('Choose a panel to add to this dashboard:'))
->appendChild(
id(new AphrontFormTokenizerControl())
->setUser($this->getViewer())
->setDatasource(new PhabricatorDashboardPanelDatasource())
->setLimit(1)
->setName('panel')
->setLabel(pht('Panel')));
return $this->newDialog()
->setTitle(pht('Add Panel'))
->setErrors($errors)
->appendChild($form->buildLayoutView())
->addCancelButton($redirect_uri)
->addSubmitButton(pht('Add Panel'));
}
}

View file

@ -1,79 +0,0 @@
<?php
final class PhabricatorDashboardArrangeController
extends PhabricatorDashboardProfileController {
public function shouldAllowPublic() {
return true;
}
public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer();
$id = $request->getURIData('id');
$dashboard = id(new PhabricatorDashboardQuery())
->setViewer($viewer)
->withIDs(array($id))
->needPanels(true)
->executeOne();
if (!$dashboard) {
return new Aphront404Response();
}
$this->setDashboard($dashboard);
$can_edit = PhabricatorPolicyFilter::hasCapability(
$viewer,
$dashboard,
PhabricatorPolicyCapability::CAN_EDIT);
$title = $dashboard->getName();
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb(pht('Arrange'));
$header = $this->buildHeaderView();
$info_view = null;
if (!$can_edit) {
$no_edit = pht(
'You do not have permission to edit this dashboard.');
$info_view = id(new PHUIInfoView())
->setSeverity(PHUIInfoView::SEVERITY_NOTICE)
->setErrors(array($no_edit));
}
$rendered_dashboard = id(new PhabricatorDashboardRenderingEngine())
->setViewer($viewer)
->setDashboard($dashboard)
->setArrangeMode($can_edit)
->renderDashboard();
$dashboard_box = id(new PHUIBoxView())
->addClass('dashboard-preview-box')
->appendChild($rendered_dashboard);
$install_button = id(new PHUIButtonView())
->setTag('a')
->setText('Install Dashboard')
->setIcon('fa-plus')
->setWorkflow(true)
->setHref($this->getApplicationURI("/install/{$id}/"));
$header->addActionLink($install_button);
$view = id(new PHUITwoColumnView())
->setHeader($header)
->setFooter(array(
$info_view,
$dashboard_box,
));
$navigation = $this->buildSideNavView('arrange');
return $this->newPage()
->setTitle($title)
->setCrumbs($crumbs)
->setNavigation($navigation)
->appendChild($view);
}
}

View file

@ -0,0 +1,72 @@
<?php
final class PhabricatorDashboardConsoleController
extends PhabricatorDashboardController {
public function shouldAllowPublic() {
return true;
}
public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer();
$menu = id(new PHUIObjectItemListView())
->setUser($viewer)
->setBig(true);
$menu->addItem(
id(new PHUIObjectItemView())
->setHeader(pht('Portals'))
->setImageIcon('fa-compass')
->setHref('/portal/')
->setClickable(true)
->addAttribute(
pht(
'Portals are collections of dashboards, links, and other '.
'resources that can provide a high-level overview of a '.
'project.')));
$menu->addItem(
id(new PHUIObjectItemView())
->setHeader(pht('Dashboards'))
->setImageIcon('fa-dashboard')
->setHref($this->getApplicationURI('/'))
->setClickable(true)
->addAttribute(
pht(
'Dashboards organize panels, creating a cohesive page for '.
'analysis or action.')));
$menu->addItem(
id(new PHUIObjectItemView())
->setHeader(pht('Panels'))
->setImageIcon('fa-line-chart')
->setHref($this->getApplicationURI('panel/'))
->setClickable(true)
->addAttribute(
pht(
'Panels show queries, charts, and other information to provide '.
'insight on a particular topic.')));
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb(pht('Console'));
$crumbs->setBorder(true);
$title = pht('Dashboard Console');
$box = id(new PHUIObjectBoxView())
->setHeaderText($title)
->setBackground(PHUIObjectBoxView::WHITE_CONFIG)
->setObjectList($menu);
$view = id(new PHUITwoColumnView())
->setFixed(true)
->setFooter($box);
return $this->newPage()
->setTitle($title)
->setCrumbs($crumbs)
->appendChild($view);
}
}

View file

@ -1,382 +0,0 @@
<?php
final class PhabricatorDashboardEditController
extends PhabricatorDashboardController {
public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer();
$id = $request->getURIData('id');
if ($id) {
$dashboard = id(new PhabricatorDashboardQuery())
->setViewer($viewer)
->withIDs(array($id))
->needPanels(true)
->requireCapabilities(
array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT,
))
->executeOne();
if (!$dashboard) {
return new Aphront404Response();
}
$v_projects = PhabricatorEdgeQuery::loadDestinationPHIDs(
$dashboard->getPHID(),
PhabricatorProjectObjectHasProjectEdgeType::EDGECONST);
$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;
}
$crumbs = $this->buildApplicationCrumbs();
if ($is_new) {
$title = pht('Create Dashboard');
$header_icon = 'fa-plus-square';
$button = pht('Create Dashboard');
$cancel_uri = $this->getApplicationURI();
$crumbs->addTextCrumb(pht('Create Dashboard'));
} else {
$id = $dashboard->getID();
$cancel_uri = $this->getApplicationURI('manage/'.$id.'/');
$title = pht('Edit Dashboard: %s', $dashboard->getName());
$header_icon = 'fa-pencil';
$button = pht('Save Changes');
$crumbs->addTextCrumb($dashboard->getName(), $cancel_uri);
$crumbs->addTextCrumb(pht('Edit'));
}
$v_name = $dashboard->getName();
$v_icon = $dashboard->getIcon();
$v_layout_mode = $dashboard->getLayoutConfigObject()->getLayoutMode();
$e_name = true;
$validation_exception = null;
if ($request->isFormPost() && $request->getStr('edit')) {
$v_name = $request->getStr('name');
$v_icon = $request->getStr('icon');
$v_layout_mode = $request->getStr('layout_mode');
$v_view_policy = $request->getStr('viewPolicy');
$v_edit_policy = $request->getStr('editPolicy');
$v_projects = $request->getArr('projects');
$xactions = array();
$type_name = PhabricatorDashboardTransaction::TYPE_NAME;
$type_icon = PhabricatorDashboardTransaction::TYPE_ICON;
$type_layout_mode = PhabricatorDashboardTransaction::TYPE_LAYOUT_MODE;
$type_view_policy = PhabricatorTransactions::TYPE_VIEW_POLICY;
$type_edit_policy = PhabricatorTransactions::TYPE_EDIT_POLICY;
$xactions[] = id(new PhabricatorDashboardTransaction())
->setTransactionType($type_name)
->setNewValue($v_name);
$xactions[] = id(new PhabricatorDashboardTransaction())
->setTransactionType($type_layout_mode)
->setNewValue($v_layout_mode);
$xactions[] = id(new PhabricatorDashboardTransaction())
->setTransactionType($type_icon)
->setNewValue($v_icon);
$xactions[] = id(new PhabricatorDashboardTransaction())
->setTransactionType($type_view_policy)
->setNewValue($v_view_policy);
$xactions[] = id(new PhabricatorDashboardTransaction())
->setTransactionType($type_edit_policy)
->setNewValue($v_edit_policy);
$proj_edge_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST;
$xactions[] = id(new PhabricatorDashboardTransaction())
->setTransactionType(PhabricatorTransactions::TYPE_EDGE)
->setMetadataValue('edge:type', $proj_edge_type)
->setNewValue(array('=' => array_fuse($v_projects)));
try {
$editor = id(new PhabricatorDashboardTransactionEditor())
->setActor($viewer)
->setContinueOnNoEffect(true)
->setContentSourceFromRequest($request)
->applyTransactions($dashboard, $xactions);
$uri = $this->getApplicationURI('arrange/'.$dashboard->getID().'/');
return id(new AphrontRedirectResponse())->setURI($uri);
} catch (PhabricatorApplicationTransactionValidationException $ex) {
$validation_exception = $ex;
$e_name = $validation_exception->getShortMessage($type_name);
$dashboard->setViewPolicy($v_view_policy);
$dashboard->setEditPolicy($v_edit_policy);
}
}
$policies = id(new PhabricatorPolicyQuery())
->setViewer($viewer)
->setObject($dashboard)
->execute();
$layout_mode_options =
PhabricatorDashboardLayoutConfig::getLayoutModeSelectOptions();
$form = id(new AphrontFormView())
->setUser($viewer)
->addHiddenInput('edit', true)
->appendChild(
id(new AphrontFormTextControl())
->setLabel(pht('Name'))
->setName('name')
->setValue($v_name)
->setError($e_name))
->appendChild(
id(new AphrontFormSelectControl())
->setLabel(pht('Layout Mode'))
->setName('layout_mode')
->setValue($v_layout_mode)
->setOptions($layout_mode_options))
->appendChild(
id(new PHUIFormIconSetControl())
->setLabel(pht('Icon'))
->setName('icon')
->setIconSet(new PhabricatorDashboardIconSet())
->setValue($v_icon))
->appendChild(
id(new AphrontFormPolicyControl())
->setName('viewPolicy')
->setPolicyObject($dashboard)
->setCapability(PhabricatorPolicyCapability::CAN_VIEW)
->setPolicies($policies))
->appendChild(
id(new AphrontFormPolicyControl())
->setName('editPolicy')
->setPolicyObject($dashboard)
->setCapability(PhabricatorPolicyCapability::CAN_EDIT)
->setPolicies($policies));
$form->appendControl(
id(new AphrontFormTokenizerControl())
->setLabel(pht('Tags'))
->setName('projects')
->setValue($v_projects)
->setDatasource(new PhabricatorProjectDatasource()));
$form->appendChild(
id(new AphrontFormSubmitControl())
->setValue($button)
->addCancelButton($cancel_uri));
$box = id(new PHUIObjectBoxView())
->setHeaderText($title)
->setForm($form)
->setBackground(PHUIObjectBoxView::WHITE_CONFIG)
->setValidationException($validation_exception);
$crumbs->setBorder(true);
$view = id(new PHUITwoColumnView())
->setFooter($box);
return $this->newPage()
->setTitle($title)
->setCrumbs($crumbs)
->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,
$type,
$name,
array $properties) {
$panel = PhabricatorDashboardPanel::initializeNewPanel($viewer)
->setPanelType($type)
->setProperties($properties);
$xactions = array();
$xactions[] = id(new PhabricatorDashboardPanelTransaction())
->setTransactionType(PhabricatorDashboardPanelTransaction::TYPE_NAME)
->setNewValue($name);
$editor = id(new PhabricatorDashboardPanelTransactionEditor())
->setActor($viewer)
->setContinueOnNoEffect(true)
->setContentSourceFromRequest($request)
->applyTransactions($panel, $xactions);
return $panel;
}
}

View file

@ -1,141 +0,0 @@
<?php
final class PhabricatorDashboardInstallController
extends PhabricatorDashboardController {
public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer();
$id = $request->getURIData('id');
$dashboard = id(new PhabricatorDashboardQuery())
->setViewer($viewer)
->withIDs(array($id))
->executeOne();
if (!$dashboard) {
return new Aphront404Response();
}
$cancel_uri = $this->getApplicationURI(
'view/'.$dashboard->getID().'/');
$home_app = new PhabricatorHomeApplication();
$options = array();
$options['home'] = array(
'personal' =>
array(
'capability' => PhabricatorPolicyCapability::CAN_VIEW,
'application' => $home_app,
'name' => pht('Personal Dashboard'),
'value' => 'personal',
'description' => pht('Places this dashboard as a menu item on home '.
'as a personal menu item. It will only be on your personal '.
'home.'),
),
'global' =>
array(
'capability' => PhabricatorPolicyCapability::CAN_EDIT,
'application' => $home_app,
'name' => pht('Global Dashboard'),
'value' => 'global',
'description' => pht('Places this dashboard as a menu item on home '.
'as a global menu item. It will be available to all users.'),
),
);
$errors = array();
$v_name = null;
if ($request->isFormPost()) {
$menuitem = new PhabricatorDashboardProfileMenuItem();
$dashboard_phid = $dashboard->getPHID();
$home = new PhabricatorHomeApplication();
$v_name = $request->getStr('name');
$v_home = $request->getStr('home');
if ($v_home) {
$application = $options['home'][$v_home]['application'];
$capability = $options['home'][$v_home]['capability'];
$can_edit_home = PhabricatorPolicyFilter::hasCapability(
$viewer,
$application,
$capability);
if (!$can_edit_home) {
$errors[] = pht(
'You do not have permission to install a dashboard on home.');
}
} else {
$errors[] = pht(
'You must select a destination to install this dashboard.');
}
$v_phid = $viewer->getPHID();
if ($v_home == 'global') {
$v_phid = null;
}
if (!$errors) {
$install = PhabricatorProfileMenuItemConfiguration::initializeNewItem(
$home,
$menuitem,
$v_phid);
$install->setMenuItemProperty('dashboardPHID', $dashboard_phid);
$install->setMenuItemProperty('name', $v_name);
$install->setMenuItemOrder(1);
$xactions = array();
$editor = id(new PhabricatorProfileMenuEditor())
->setActor($viewer)
->setContinueOnNoEffect(true)
->setContinueOnMissingFields(true)
->setContentSourceFromRequest($request);
$editor->applyTransactions($install, $xactions);
$view_uri = '/home/menu/view/'.$install->getID().'/';
return id(new AphrontRedirectResponse())->setURI($view_uri);
}
}
$form = id(new AphrontFormView())
->setUser($viewer)
->appendChild(
id(new AphrontFormTextControl())
->setLabel(pht('Menu Label'))
->setName('name')
->setValue($v_name));
$radio = id(new AphrontFormRadioButtonControl())
->setLabel(pht('Home Menu'))
->setName('home');
foreach ($options['home'] as $type => $option) {
$can_edit = PhabricatorPolicyFilter::hasCapability(
$viewer,
$option['application'],
$option['capability']);
if ($can_edit) {
$radio->addButton(
$option['value'],
$option['name'],
$option['description']);
}
}
$form->appendChild($radio);
return $this->newDialog()
->setTitle(pht('Install Dashboard'))
->setErrors($errors)
->setWidth(AphrontDialogView::WIDTH_FORM)
->appendChild($form->buildLayoutView())
->addCancelButton($cancel_uri)
->addSubmitButton(pht('Install Dashboard'));
}
}

View file

@ -28,9 +28,6 @@ final class PhabricatorDashboardListController
->setViewer($user)
->addNavigationItems($nav->getMenu());
$nav->addLabel(pht('Panels'));
$nav->addFilter('panel/', pht('Manage Panels'));
$nav->selectFilter(null);
return $nav;
@ -39,11 +36,9 @@ final class PhabricatorDashboardListController
protected function buildApplicationCrumbs() {
$crumbs = parent::buildApplicationCrumbs();
$crumbs->addAction(
id(new PHUIListItemView())
->setIcon('fa-plus-square')
->setName(pht('Create Dashboard'))
->setHref($this->getApplicationURI().'create/'));
id(new PhabricatorDashboardEditEngine())
->setViewer($this->getViewer())
->addActionToCrumbs($crumbs);
return $crumbs;
}

View file

@ -1,139 +0,0 @@
<?php
final class PhabricatorDashboardManageController
extends PhabricatorDashboardProfileController {
public function shouldAllowPublic() {
return true;
}
public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer();
$id = $request->getURIData('id');
// TODO: This UI should drop a lot of capabilities if the user can't
// edit the dashboard, but we should still let them in for "Install" and
// "View History".
$dashboard = id(new PhabricatorDashboardQuery())
->setViewer($viewer)
->withIDs(array($id))
->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('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.');
$info_view = id(new PHUIInfoView())
->setSeverity(PHUIInfoView::SEVERITY_NOTICE)
->setErrors(array($no_edit));
}
$view = id(new PHUITwoColumnView())
->setHeader($header)
->setCurtain($curtain)
->setMainColumn(array(
$info_view,
$properties,
$timeline,
));
$navigation = $this->buildSideNavView('manage');
return $this->newPage()
->setTitle($title)
->setCrumbs($crumbs)
->setNavigation($navigation)
->appendChild($view);
}
private function buildCurtainView(PhabricatorDashboard $dashboard) {
$viewer = $this->getViewer();
$id = $dashboard->getID();
$curtain = $this->newCurtainView($dashboard);
$can_edit = PhabricatorPolicyFilter::hasCapability(
$viewer,
$dashboard,
PhabricatorPolicyCapability::CAN_EDIT);
$curtain->addAction(
id(new PhabricatorActionView())
->setName(pht('Edit Dashboard'))
->setIcon('fa-pencil')
->setHref($this->getApplicationURI("edit/{$id}/"))
->setDisabled(!$can_edit));
if ($dashboard->isArchived()) {
$curtain->addAction(
id(new PhabricatorActionView())
->setName(pht('Activate Dashboard'))
->setIcon('fa-check')
->setHref($this->getApplicationURI("archive/{$id}/"))
->setDisabled(!$can_edit)
->setWorkflow($can_edit));
} else {
$curtain->addAction(
id(new PhabricatorActionView())
->setName(pht('Archive Dashboard'))
->setIcon('fa-ban')
->setHref($this->getApplicationURI("archive/{$id}/"))
->setDisabled(!$can_edit)
->setWorkflow($can_edit));
}
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);
}
}

View file

@ -1,71 +0,0 @@
<?php
final class PhabricatorDashboardMovePanelController
extends PhabricatorDashboardController {
public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer();
$id = $request->getURIData('id');
$column_id = $request->getStr('columnID');
$panel_phid = $request->getStr('objectPHID');
$after_phid = $request->getStr('afterPHID');
$before_phid = $request->getStr('beforePHID');
$dashboard = id(new PhabricatorDashboardQuery())
->setViewer($viewer)
->withIDs(array($id))
->needPanels(true)
->requireCapabilities(
array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT,
))
->executeOne();
if (!$dashboard) {
return new Aphront404Response();
}
$panels = mpull($dashboard->getPanels(), null, 'getPHID');
$panel = idx($panels, $panel_phid);
if (!$panel) {
return new Aphront404Response();
}
$layout_config = $dashboard->getLayoutConfigObject();
$layout_config->removePanel($panel_phid);
$panel_location_grid = $layout_config->getPanelLocations();
$column_phids = idx($panel_location_grid, $column_id, array());
$column_phids = array_values($column_phids);
if ($column_phids) {
$insert_at = 0;
foreach ($column_phids as $index => $phid) {
if ($phid === $before_phid) {
$insert_at = $index;
break;
}
if ($phid === $after_phid) {
$insert_at = $index + 1;
break;
}
}
$new_column_phids = $column_phids;
array_splice(
$new_column_phids,
$insert_at,
0,
array($panel_phid));
} else {
$new_column_phids = array(0 => $panel_phid);
}
$panel_location_grid[$column_id] = $new_column_phids;
$layout_config->setPanelLocations($panel_location_grid);
$dashboard->setLayoutConfigFromObject($layout_config);
$dashboard->save();
return id(new AphrontAjaxResponse())->setContent('');
}
}

View file

@ -1,354 +0,0 @@
<?php
final class PhabricatorDashboardPanelEditController
extends PhabricatorDashboardController {
public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer();
$id = $request->getURIData('id');
// If the user is trying to create a panel directly on a dashboard, make
// sure they have permission to see and edit the dashboard.
$dashboard_id = $request->getInt('dashboardID');
$dashboard = null;
if ($dashboard_id) {
$dashboard = id(new PhabricatorDashboardQuery())
->setViewer($viewer)
->withIDs(array($dashboard_id))
->requireCapabilities(
array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT,
))
->executeOne();
if (!$dashboard) {
return new Aphront404Response();
}
$manage_uri = $this->getApplicationURI('arrange/'.$dashboard_id.'/');
}
if ($id) {
$is_create = false;
if ($dashboard) {
$capabilities = array(
PhabricatorPolicyCapability::CAN_VIEW,
);
} else {
$capabilities = array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT,
);
}
$panel = id(new PhabricatorDashboardPanelQuery())
->setViewer($viewer)
->withIDs(array($id))
->requireCapabilities($capabilities)
->executeOne();
if (!$panel) {
return new Aphront404Response();
}
} else {
$is_create = true;
$panel = PhabricatorDashboardPanel::initializeNewPanel($viewer);
$types = PhabricatorDashboardPanelType::getAllPanelTypes();
$type = $request->getStr('type');
if (empty($types[$type])) {
return $this->processPanelTypeRequest($request);
}
$panel->setPanelType($type);
}
if ($is_create) {
$title = pht('Create New Panel');
$button = pht('Create Panel');
$header_icon = 'fa-plus-square';
if ($dashboard) {
$cancel_uri = $manage_uri;
} else {
$cancel_uri = $this->getApplicationURI('panel/');
}
} else {
$title = pht('Edit Panel: %s', $panel->getName());
$button = pht('Save Panel');
$header_icon = 'fa-pencil';
if ($dashboard) {
$cancel_uri = $manage_uri;
} else {
$cancel_uri = '/'.$panel->getMonogram();
}
}
$v_name = $panel->getName();
$e_name = true;
$field_list = PhabricatorCustomField::getObjectFields(
$panel,
PhabricatorCustomField::ROLE_EDIT);
$field_list
->setViewer($viewer)
->readFieldsFromStorage($panel);
if ($is_create && !$request->isFormPost()) {
$panel->requireImplementation()->initializeFieldsFromRequest(
$panel,
$field_list,
$request);
}
$validation_exception = null;
// NOTE: We require 'edit' to distinguish between the "Choose a Type"
// and "Create a Panel" dialogs.
if ($request->isFormPost() && $request->getBool('edit')) {
$v_name = $request->getStr('name');
$v_view_policy = $request->getStr('viewPolicy');
$v_edit_policy = $request->getStr('editPolicy');
$type_name = PhabricatorDashboardPanelTransaction::TYPE_NAME;
$type_view_policy = PhabricatorTransactions::TYPE_VIEW_POLICY;
$type_edit_policy = PhabricatorTransactions::TYPE_EDIT_POLICY;
$xactions = array();
$xactions[] = id(new PhabricatorDashboardPanelTransaction())
->setTransactionType($type_name)
->setNewValue($v_name);
$xactions[] = id(new PhabricatorDashboardPanelTransaction())
->setTransactionType($type_view_policy)
->setNewValue($v_view_policy);
$xactions[] = id(new PhabricatorDashboardPanelTransaction())
->setTransactionType($type_edit_policy)
->setNewValue($v_edit_policy);
$field_xactions = $field_list->buildFieldTransactionsFromRequest(
new PhabricatorDashboardPanelTransaction(),
$request);
$xactions = array_merge($xactions, $field_xactions);
try {
$editor = id(new PhabricatorDashboardPanelTransactionEditor())
->setActor($viewer)
->setContinueOnNoEffect(true)
->setContentSourceFromRequest($request)
->applyTransactions($panel, $xactions);
// If we're creating a panel directly on a dashboard, add it now.
if ($dashboard && $is_create) {
PhabricatorDashboardTransactionEditor::addPanelToDashboard(
$viewer,
PhabricatorContentSource::newFromRequest($request),
$panel,
$dashboard,
$request->getInt('column', 0));
}
if ($dashboard) {
$done_uri = $manage_uri;
} else {
$done_uri = '/'.$panel->getMonogram();
}
return id(new AphrontRedirectResponse())->setURI($done_uri);
} catch (PhabricatorApplicationTransactionValidationException $ex) {
$validation_exception = $ex;
$e_name = $validation_exception->getShortMessage($type_name);
$panel->setViewPolicy($v_view_policy);
$panel->setEditPolicy($v_edit_policy);
}
}
// NOTE: We're setting the submit URI explicitly because we need to edit
// a different panel if we just cloned the original panel.
if ($is_create) {
$submit_uri = $this->getApplicationURI('panel/edit/');
} else {
$submit_uri = $this->getApplicationURI('panel/edit/'.$panel->getID().'/');
}
$policies = id(new PhabricatorPolicyQuery())
->setViewer($viewer)
->setObject($panel)
->execute();
$form = id(new AphrontFormView())
->setUser($viewer)
->setAction($submit_uri)
->addHiddenInput('edit', true)
->addHiddenInput('dashboardID', $request->getInt('dashboardID'))
->addHiddenInput('column', $request->getInt('column'))
->appendChild(
id(new AphrontFormTextControl())
->setLabel(pht('Name'))
->setName('name')
->setValue($v_name)
->setError($e_name));
if (!$request->isAjax() || !$is_create) {
$form
->appendChild(
id(new AphrontFormPolicyControl())
->setName('viewPolicy')
->setPolicyObject($panel)
->setCapability(PhabricatorPolicyCapability::CAN_VIEW)
->setPolicies($policies))
->appendChild(
id(new AphrontFormPolicyControl())
->setName('editPolicy')
->setPolicyObject($panel)
->setCapability(PhabricatorPolicyCapability::CAN_EDIT)
->setPolicies($policies));
}
$field_list->appendFieldsToForm($form);
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb(
pht('Panels'),
$this->getApplicationURI('panel/'));
if ($is_create) {
$crumbs->addTextCrumb(pht('New Panel'));
$form->addHiddenInput('type', $panel->getPanelType());
} else {
$crumbs->addTextCrumb(
$panel->getMonogram(),
'/'.$panel->getMonogram());
$crumbs->addTextCrumb(pht('Edit'));
}
$crumbs->setBorder(true);
if ($request->isAjax()) {
return $this->newDialog()
->setTitle($title)
->setSubmitURI($submit_uri)
->setWidth(AphrontDialogView::WIDTH_FORM)
->setValidationException($validation_exception)
->appendChild($form->buildLayoutView())
->addCancelButton($cancel_uri)
->addSubmitButton($button);
} else {
$form
->appendChild(
id(new AphrontFormSubmitControl())
->setValue($button)
->addCancelButton($cancel_uri));
}
$box = id(new PHUIObjectBoxView())
->setHeaderText(pht('Panel'))
->setValidationException($validation_exception)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setForm($form);
$header = id(new PHUIHeaderView())
->setHeader($title)
->setHeaderIcon($header_icon);
$view = id(new PHUITwoColumnView())
->setHeader($header)
->setFooter($box);
return $this->newPage()
->setTitle($title)
->setCrumbs($crumbs)
->appendChild($view);
}
private function processPanelTypeRequest(AphrontRequest $request) {
$viewer = $request->getUser();
$types = PhabricatorDashboardPanelType::getAllPanelTypes();
$v_type = null;
$errors = array();
if ($request->isFormPost()) {
$v_type = $request->getStr('type');
if (!isset($types[$v_type])) {
$errors[] = pht('You must select a type of panel to create.');
}
}
$cancel_uri = $this->getApplicationURI('panel/');
if (!$v_type) {
$v_type = key($types);
}
$panel_types = id(new AphrontFormRadioButtonControl())
->setName('type')
->setValue($v_type);
foreach ($types as $key => $type) {
$panel_types->addButton(
$key,
$type->getPanelTypeName(),
$type->getPanelTypeDescription());
}
$form = id(new AphrontFormView())
->setUser($viewer)
->addHiddenInput('dashboardID', $request->getInt('dashboardID'))
->addHiddenInput('column', $request->getInt('column'))
->appendRemarkupInstructions(
pht(
'Choose the type of dashboard panel to create:'))
->appendChild($panel_types);
if ($request->isAjax()) {
return $this->newDialog()
->setTitle(pht('Add New Panel'))
->setWidth(AphrontDialogView::WIDTH_FORM)
->setErrors($errors)
->appendChild($form->buildLayoutView())
->addCancelbutton($cancel_uri)
->addSubmitButton(pht('Continue'));
} else {
$form->appendChild(
id(new AphrontFormSubmitControl())
->setValue(pht('Continue'))
->addCancelButton($cancel_uri));
}
$title = pht('Create Dashboard Panel');
$header_icon = 'fa-plus-square';
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb(
pht('Panels'),
$this->getApplicationURI('panel/'));
$crumbs->addTextCrumb(pht('New Panel'));
$crumbs->setBorder(true);
$box = id(new PHUIObjectBoxView())
->setHeaderText(pht('Panel'))
->setFormErrors($errors)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setForm($form);
$header = id(new PHUIHeaderView())
->setHeader($title)
->setHeaderIcon($header_icon);
$view = id(new PHUITwoColumnView())
->setHeader($header)
->setFooter($box);
return $this->newPage()
->setTitle($title)
->setCrumbs($crumbs)
->appendChild($view);
}
}

View file

@ -1,105 +0,0 @@
<?php
final class PhabricatorDashboardPanelEditproController
extends PhabricatorDashboardController {
public function handleRequest(AphrontRequest $request) {
$engine = id(new PhabricatorDashboardPanelEditEngine())
->setController($this);
$id = $request->getURIData('id');
if (!$id) {
$list_uri = $this->getApplicationURI('panel/');
$panel_type = $request->getStr('panelType');
$panel_types = PhabricatorDashboardPanelType::getAllPanelTypes();
if (empty($panel_types[$panel_type])) {
return $this->buildPanelTypeResponse($list_uri);
}
$engine
->addContextParameter('panelType', $panel_type)
->setPanelType($panel_type);
}
return $engine->buildResponse();
}
private function buildPanelTypeResponse($cancel_uri) {
$panel_types = PhabricatorDashboardPanelType::getAllPanelTypes();
$viewer = $this->getViewer();
$request = $this->getRequest();
$e_type = null;
$errors = array();
if ($request->isFormPost()) {
$e_type = pht('Required');
$errors[] = pht(
'To create a new dashboard panel, you must select a panel type.');
}
$type_control = id(new AphrontFormRadioButtonControl())
->setLabel(pht('Panel Type'))
->setName('panelType')
->setError($e_type);
foreach ($panel_types as $key => $type) {
$type_control->addButton(
$key,
$type->getPanelTypeName(),
$type->getPanelTypeDescription());
}
$form = id(new AphrontFormView())
->setUser($viewer)
->appendRemarkupInstructions(
pht('Choose the type of dashboard panel to create:'))
->appendChild($type_control);
if ($request->isAjax()) {
return $this->newDialog()
->setTitle(pht('Add New Panel'))
->setWidth(AphrontDialogView::WIDTH_FORM)
->setErrors($errors)
->appendForm($form)
->addCancelButton($cancel_uri)
->addSubmitButton(pht('Continue'));
}
$form->appendChild(
id(new AphrontFormSubmitControl())
->setValue(pht('Continue'))
->addCancelButton($cancel_uri));
$title = pht('Create Dashboard Panel');
$header_icon = 'fa-plus-square';
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb(
pht('Panels'),
$this->getApplicationURI('panel/'));
$crumbs->addTextCrumb(pht('New Panel'));
$crumbs->setBorder(true);
$box = id(new PHUIObjectBoxView())
->setHeaderText(pht('Panel'))
->setFormErrors($errors)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->setForm($form);
$header = id(new PHUIHeaderView())
->setHeader($title)
->setHeaderIcon($header_icon);
$view = id(new PHUITwoColumnView())
->setHeader($header)
->setFooter($box);
return $this->newPage()
->setTitle($title)
->setCrumbs($crumbs)
->appendChild($view);
}
}

View file

@ -14,10 +14,6 @@ abstract class PhabricatorDashboardProfileController
return $this->dashboard;
}
public function buildApplicationMenu() {
return $this->buildSideNavView()->getMenu();
}
protected function buildHeaderView() {
$viewer = $this->getViewer();
$dashboard = $this->getDashboard();
@ -49,50 +45,10 @@ abstract class PhabricatorDashboardProfileController
$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;
}
}

View file

@ -7,185 +7,160 @@ final class PhabricatorDashboardQueryPanelInstallController
$viewer = $request->getViewer();
$v_dashboard = null;
$v_name = null;
$v_column = 0;
$v_engine = $request->getURIData('engineKey');
$v_query = $request->getURIData('queryKey');
$e_dashboard = null;
$v_name = null;
$e_name = true;
// Validate Engines
$v_engine = $request->getStr('engine');
if (!strlen($v_engine)) {
$v_engine = $request->getURIData('engineKey');
}
$v_query = $request->getStr('query');
if (!strlen($v_query)) {
$v_query = $request->getURIData('queryKey');
}
$engines = PhabricatorApplicationSearchEngine::getAllEngines();
foreach ($engines as $name => $engine) {
if (!$engine->canUseInPanelContext()) {
unset($engines[$name]);
}
}
if (!in_array($v_engine, array_keys($engines))) {
return new Aphront404Response();
}
$engine = idx($engines, $v_engine);
if ($engine) {
$engine = id(clone $engine)
->setViewer($viewer);
// Validate Queries
$engine = $engines[$v_engine];
$engine->setViewer($viewer);
$good_query = false;
if ($engine->isBuiltinQuery($v_query)) {
$good_query = true;
$redirect_uri = $engine->getQueryResultsPageURI($v_query);
$named_query = idx($engine->loadEnabledNamedQueries(), $v_query);
if ($named_query) {
$v_name = $named_query->getQueryName();
}
} else {
$saved_query = id(new PhabricatorSavedQueryQuery())
->setViewer($viewer)
->withEngineClassNames(array($v_engine))
->withQueryKeys(array($v_query))
->executeOne();
if ($saved_query) {
$good_query = true;
}
}
if (!$good_query) {
return new Aphront404Response();
}
$named_query = idx($engine->loadEnabledNamedQueries(), $v_query);
if ($named_query) {
$v_name = $named_query->getQueryName();
$redirect_uri = '/';
}
$errors = array();
$xaction_name = PhabricatorDashboardPanelNameTransaction::TRANSACTIONTYPE;
$xaction_engine =
PhabricatorDashboardQueryPanelApplicationTransaction::TRANSACTIONTYPE;
$xaction_query =
PhabricatorDashboardQueryPanelQueryTransaction::TRANSACTIONTYPE;
if ($request->isFormPost()) {
$v_dashboard = $request->getInt('dashboardID');
$v_name = $request->getStr('name');
if (!$v_name) {
$errors[] = pht('You must provide a name for this panel.');
$e_name = pht('Required');
}
$dashboard = id(new PhabricatorDashboardQuery())
->setViewer($viewer)
->withIDs(array($v_dashboard))
->requireCapabilities(
array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT,
))
->executeOne();
$v_dashboard = head($request->getArr('dashboardPHIDs'));
if (!$v_dashboard) {
$errors[] = pht('You must select a dashboard.');
$e_dashboard = pht('Required');
} else {
$dashboard = id(new PhabricatorDashboardQuery())
->setViewer($viewer)
->withPHIDs(array($v_dashboard))
->executeOne();
if (!$dashboard) {
$errors[] = pht('You must select a valid dashboard.');
$e_dashboard = pht('Invalid');
}
if (!$dashboard) {
$errors[] = pht('Please select a valid dashboard.');
$can_edit = PhabricatorPolicyFilter::hasCapability(
$viewer,
$dashboard,
PhabricatorPolicyCapability::CAN_EDIT);
if (!$can_edit) {
$errors[] = pht(
'You must select a dashboard you have permission to edit.');
}
}
if (!$errors) {
$redirect_uri = "/dashboard/arrange/{$v_dashboard}/";
$done_uri = $dashboard->getURI();
// First, create a new panel.
$panel_type = id(new PhabricatorDashboardQueryPanelType())
->getPanelTypeKey();
$panel = PhabricatorDashboardPanel::initializeNewPanel($viewer);
$panel->setPanelType($panel_type);
$field_list = PhabricatorCustomField::getObjectFields(
$panel,
PhabricatorCustomField::ROLE_EDIT);
$field_list
->setViewer($viewer)
->readFieldsFromStorage($panel);
$panel->requireImplementation()->initializeFieldsFromRequest(
$panel,
$field_list,
$request);
$panel = PhabricatorDashboardPanel::initializeNewPanel($viewer)
->setPanelType($panel_type);
$xactions = array();
$xactions[] = id(new PhabricatorDashboardPanelTransaction())
->setTransactionType(PhabricatorDashboardPanelTransaction::TYPE_NAME)
->setNewValue($v_name);
$xactions[] = id(new PhabricatorDashboardPanelTransaction())
->setTransactionType(PhabricatorTransactions::TYPE_CUSTOMFIELD)
->setMetadataValue('customfield:key', 'std:dashboard:core:class')
->setOldValue(null)
$xactions[] = $panel->getApplicationTransactionTemplate()
->setTransactionType($xaction_engine)
->setNewValue($v_engine);
$xactions[] = id(new PhabricatorDashboardPanelTransaction())
->setTransactionType(PhabricatorTransactions::TYPE_CUSTOMFIELD)
->setMetadataValue('customfield:key', 'std:dashboard:core:key')
->setOldValue(null)
$xactions[] = $panel->getApplicationTransactionTemplate()
->setTransactionType($xaction_query)
->setNewValue($v_query);
$editor = id(new PhabricatorDashboardPanelTransactionEditor())
$xactions[] = $panel->getApplicationTransactionTemplate()
->setTransactionType($xaction_name)
->setNewValue($v_name);
$editor = $panel->getApplicationTransactionEditor()
->setActor($viewer)
->setContinueOnNoEffect(true)
->setContentSourceFromRequest($request)
->applyTransactions($panel, $xactions);
PhabricatorDashboardTransactionEditor::addPanelToDashboard(
$viewer,
PhabricatorContentSource::newFromRequest($request),
$panel,
$dashboard,
$request->getInt('column', 0));
// Now that we've created a panel, add it to the dashboard.
return id(new AphrontRedirectResponse())->setURI($redirect_uri);
$xactions = array();
$ref_list = clone $dashboard->getPanelRefList();
$ref_list->newPanelRef($panel);
$new_panels = $ref_list->toDictionary();
$xactions[] = $dashboard->getApplicationTransactionTemplate()
->setTransactionType(
PhabricatorDashboardPanelsTransaction::TRANSACTIONTYPE)
->setNewValue($new_panels);
$editor = $dashboard->getApplicationTransactionEditor()
->setActor($viewer)
->setContentSourceFromRequest($request)
->setContinueOnNoEffect(true)
->setContinueOnMissingFields(true)
->applyTransactions($dashboard, $xactions);
return id(new AphrontRedirectResponse())->setURI($done_uri);
}
}
// Make this a select for now, as we don't expect someone to have
// edit access to a vast number of dashboards.
// Can add optiongroup if needed down the road.
$dashboards = id(new PhabricatorDashboardQuery())
->setViewer($viewer)
->withStatuses(array(
PhabricatorDashboard::STATUS_ACTIVE,
))
->requireCapabilities(
array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT,
))
->execute();
$options = mpull($dashboards, 'getName', 'getID');
asort($options);
$redirect_uri = $engine->getQueryResultsPageURI($v_query);
if (!$options) {
$notice = id(new PHUIInfoView())
->setSeverity(PHUIInfoView::SEVERITY_NOTICE)
->appendChild(pht('You do not have access to any dashboards. To '.
'continue, please create a dashboard first.'));
return $this->newDialog()
->setTitle(pht('No Dashboards'))
->setWidth(AphrontDialogView::WIDTH_FORM)
->appendChild($notice)
->addCancelButton($redirect_uri);
if ($v_dashboard) {
$dashboard_phids = array($v_dashboard);
} else {
$dashboard_phids = array();
}
$form = id(new AphrontFormView())
->setUser($viewer)
->addHiddenInput('engine', $v_engine)
->addHiddenInput('query', $v_query)
->addHiddenInput('column', $v_column)
->appendChild(
->setViewer($viewer)
->appendControl(
id(new AphrontFormTextControl())
->setLabel(pht('Name'))
->setName('name')
->setValue($v_name)
->setError($e_name))
->appendChild(
id(new AphrontFormSelectControl())
->setUser($this->getViewer())
->setValue($v_dashboard)
->setName('dashboardID')
->setOptions($options)
->appendControl(
id(new AphrontFormTokenizerControl())
->setValue($dashboard_phids)
->setError($e_dashboard)
->setName('dashboardPHIDs')
->setLimit(1)
->setDatasource(new PhabricatorDashboardDatasource())
->setLabel(pht('Dashboard')));
return $this->newDialog()
->setTitle(pht('Add Panel to Dashboard'))
->setErrors($errors)
->setWidth(AphrontDialogView::WIDTH_FORM)
->appendChild($form->buildLayoutView())
->addHiddenInput('engine', $v_engine)
->addHiddenInput('query', $v_query)
->appendForm($form)
->addCancelButton($redirect_uri)
->addSubmitButton(pht('Add Panel'));

View file

@ -1,89 +0,0 @@
<?php
final class PhabricatorDashboardRemovePanelController
extends PhabricatorDashboardController {
public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer();
$id = $request->getURIData('id');
$dashboard = id(new PhabricatorDashboardQuery())
->setViewer($viewer)
->withIDs(array($id))
->requireCapabilities(
array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT,
))
->executeOne();
if (!$dashboard) {
return new Aphront404Response();
}
// NOTE: If you can edit a dashboard, you can remove panels from it even
// if you don't have permission to see them or they aren't valid. We only
// require that the panel be present on the dashboard.
$v_panel = $request->getStr('panelPHID');
$panel_on_dashboard = false;
$layout = $dashboard->getLayoutConfigObject();
$columns = $layout->getPanelLocations();
foreach ($columns as $column) {
foreach ($column as $column_panel_phid) {
if ($column_panel_phid == $v_panel) {
$panel_on_dashboard = true;
break;
}
}
}
if (!$panel_on_dashboard) {
return new Aphront404Response();
}
$redirect_uri = $this->getApplicationURI(
'arrange/'.$dashboard->getID().'/');
$layout_config = $dashboard->getLayoutConfigObject();
if ($request->isFormPost()) {
$xactions = array();
$xactions[] = id(new PhabricatorDashboardTransaction())
->setTransactionType(PhabricatorTransactions::TYPE_EDGE)
->setMetadataValue(
'edge:type',
PhabricatorDashboardDashboardHasPanelEdgeType::EDGECONST)
->setNewValue(
array(
'-' => array(
$v_panel => $v_panel,
),
));
$layout_config->removePanel($v_panel);
$dashboard->setLayoutConfigFromObject($layout_config);
$editor = id(new PhabricatorDashboardTransactionEditor())
->setActor($viewer)
->setContentSourceFromRequest($request)
->setContinueOnMissingFields(true)
->setContinueOnNoEffect(true)
->applyTransactions($dashboard, $xactions);
return id(new AphrontRedirectResponse())->setURI($redirect_uri);
}
$form = id(new AphrontFormView())
->setUser($viewer)
->addHiddenInput('confirm', true)
->addHiddenInput('panelPHID', $v_panel)
->appendChild(pht('Are you sure you want to remove this panel?'));
return $this->newDialog()
->setTitle(pht('Remove Panel'))
->appendChild($form->buildLayoutView())
->addCancelButton($redirect_uri)
->addSubmitButton(pht('Remove Panel'));
}
}

View file

@ -1,68 +0,0 @@
<?php
final class PhabricatorDashboardViewController
extends PhabricatorDashboardProfileController {
public function shouldAllowPublic() {
return true;
}
public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer();
$id = $request->getURIData('id');
$dashboard = id(new PhabricatorDashboardQuery())
->setViewer($viewer)
->withIDs(array($id))
->needPanels(true)
->executeOne();
if (!$dashboard) {
return new Aphront404Response();
}
$this->setDashboard($dashboard);
$dashboard_uri = $this->getApplicationURI("view/{$id}/");
$title = $dashboard->getName();
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb(pht('View'));
if ($dashboard->getPanelPHIDs()) {
$rendered_dashboard = id(new PhabricatorDashboardRenderingEngine())
->setViewer($viewer)
->setDashboard($dashboard)
->renderDashboard();
$content = id(new PHUIBoxView())
->addClass('dashboard-preview-box')
->appendChild($rendered_dashboard);
} else {
$content = id(new PHUIInfoView())
->setSeverity(PHUIInfoView::SEVERITY_NOTICE)
->appendChild(pht('This dashboard has no panels yet.'));
}
$navigation = $this->buildSideNavView('view');
$header = $this->buildHeaderView();
$install_button = id(new PHUIButtonView())
->setTag('a')
->setText('Install Dashboard')
->setIcon('fa-plus')
->setColor(PHUIButtonView::GREEN)
->setWorkflow(true)
->setHref($this->getApplicationURI("/install/{$id}/"));
$header->addActionLink($install_button);
$view = id(new PHUITwoColumnView())
->setHeader($header)
->setFooter(array(
$content,
));
return $this->newPage()
->setTitle($title)
->setCrumbs($crumbs)
->setNavigation($navigation)
->appendChild($view);
}
}

View file

@ -0,0 +1,243 @@
<?php
final class PhabricatorDashboardAdjustController
extends PhabricatorDashboardController {
private $contextPHID;
private $panelKey;
private $columnKey;
public function handleRequest(AphrontRequest $request) {
$viewer = $this->getViewer();
$context_phid = $request->getStr('contextPHID');
$dashboard = id(new PhabricatorDashboardQuery())
->setViewer($viewer)
->withPHIDs(array($context_phid))
->requireCapabilities(
array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT,
))
->executeOne();
if (!$dashboard) {
return new Aphront404Response();
}
$this->contextPHID = $context_phid;
$done_uri = $dashboard->getURI();
$ref_list = $dashboard->getPanelRefList();
$panel_ref = null;
$panel_key = $request->getStr('panelKey');
if (strlen($panel_key)) {
$panel_ref = $ref_list->getPanelRef($panel_key);
if (!$panel_ref) {
return new Aphront404Response();
}
$this->panelKey = $panel_key;
}
$column_key = $request->getStr('columnKey');
if (strlen($column_key)) {
$columns = $ref_list->getColumns();
if (!isset($columns[$column_key])) {
return new Aphront404Response();
}
$this->columnKey = $column_key;
}
$after_ref = null;
$after_key = $request->getStr('afterKey');
if (strlen($after_key)) {
$after_ref = $ref_list->getPanelRef($after_key);
if (!$after_ref) {
return new Aphront404Response();
}
}
switch ($request->getURIData('op')) {
case 'add':
return $this->handleAddRequest($dashboard, $done_uri);
case 'remove':
if (!$panel_ref) {
return new Aphront404Response();
}
return $this->handleRemoveRequest($dashboard, $panel_ref, $done_uri);
case 'move':
return $this->handleMoveRequest($dashboard, $panel_ref, $after_ref);
}
}
private function handleAddRequest(
PhabricatorDashboard $dashboard,
$done_uri) {
$request = $this->getRequest();
$viewer = $this->getViewer();
$errors = array();
$panel_phid = null;
$e_panel = true;
if ($request->isFormPost()) {
$panel_phid = head($request->getArr('panelPHIDs'));
if (!$panel_phid) {
$errors[] = pht('You must choose a panel to add to the dashboard.');
$e_panel = pht('Required');
} else {
$panel = id(new PhabricatorDashboardPanelQuery())
->setViewer($viewer)
->withPHIDs(array($panel_phid))
->executeOne();
if (!$panel) {
$errors[] = pht('You must choose a valid panel.');
$e_panel = pht('Invalid');
}
}
if (!$errors) {
$xactions = array();
$ref_list = clone $dashboard->getPanelRefList();
$ref_list->newPanelRef($panel, $this->columnKey);
$new_panels = $ref_list->toDictionary();
$xactions[] = $dashboard->getApplicationTransactionTemplate()
->setTransactionType(
PhabricatorDashboardPanelsTransaction::TRANSACTIONTYPE)
->setNewValue($new_panels);
$editor = $dashboard->getApplicationTransactionEditor()
->setActor($viewer)
->setContentSourceFromRequest($request)
->setContinueOnNoEffect(true)
->setContinueOnMissingFields(true);
$editor->applyTransactions($dashboard, $xactions);
return id(new AphrontRedirectResponse())->setURI($done_uri);
}
}
if ($panel_phid) {
$panel_phids = array($panel_phid);
} else {
$panel_phids = array();
}
$form = id(new AphrontFormView())
->setViewer($viewer)
->appendRemarkupInstructions(
pht('Choose a panel to add to this dashboard:'))
->appendControl(
id(new AphrontFormTokenizerControl())
->setDatasource(new PhabricatorDashboardPanelDatasource())
->setLimit(1)
->setName('panelPHIDs')
->setLabel(pht('Panel'))
->setError($e_panel)
->setValue($panel_phids));
return $this->newEditDialog()
->setTitle(pht('Add Panel'))
->setWidth(AphrontDialogView::WIDTH_FORM)
->setErrors($errors)
->appendForm($form)
->addCancelButton($done_uri)
->addSubmitButton(pht('Add Panel'));
}
private function handleRemoveRequest(
PhabricatorDashboard $dashboard,
PhabricatorDashboardPanelRef $panel_ref,
$done_uri) {
$request = $this->getRequest();
$viewer = $this->getViewer();
// NOTE: If you can edit a dashboard, you can remove panels from it even
// if you don't have permission to see them or they aren't valid. We only
// require that the panel be present on the dashboard.
if ($request->isFormPost()) {
$xactions = array();
$ref_list = clone $dashboard->getPanelRefList();
$ref_list->removePanelRef($panel_ref);
$new_panels = $ref_list->toDictionary();
$xactions[] = $dashboard->getApplicationTransactionTemplate()
->setTransactionType(
PhabricatorDashboardPanelsTransaction::TRANSACTIONTYPE)
->setNewValue($new_panels);
$editor = $dashboard->getApplicationTransactionEditor()
->setActor($viewer)
->setContentSourceFromRequest($request)
->setContinueOnNoEffect(true)
->setContinueOnMissingFields(true);
$editor->applyTransactions($dashboard, $xactions);
return id(new AphrontRedirectResponse())->setURI($done_uri);
}
$panel_phid = $panel_ref->getPanelPHID();
$handles = $viewer->loadHandles(array($panel_phid));
$handle = $handles[$panel_phid];
$message = pht(
'Remove panel %s from dashboard %s?',
phutil_tag('strong', array(), $handle->getFullName()),
phutil_tag('strong', array(), $dashboard->getName()));
return $this->newEditDialog()
->setTitle(pht('Remove Dashboard Panel'))
->appendParagraph($message)
->addCancelButton($done_uri)
->addSubmitButton(pht('Remove Panel'));
}
private function handleMoveRequest(
PhabricatorDashboard $dashboard,
PhabricatorDashboardPanelRef $panel_ref,
PhabricatorDashboardPanelRef $after_ref = null) {
$request = $this->getRequest();
$request->validateCSRF();
$viewer = $this->getViewer();
$xactions = array();
$ref_list = clone $dashboard->getPanelRefList();
$ref_list->movePanelRef($panel_ref, $this->columnKey, $after_ref);
$new_panels = $ref_list->toDictionary();
$xactions[] = $dashboard->getApplicationTransactionTemplate()
->setTransactionType(
PhabricatorDashboardPanelsTransaction::TRANSACTIONTYPE)
->setNewValue($new_panels);
$editor = $dashboard->getApplicationTransactionEditor()
->setActor($viewer)
->setContentSourceFromRequest($request)
->setContinueOnNoEffect(true)
->setContinueOnMissingFields(true);
$editor->applyTransactions($dashboard, $xactions);
return id(new AphrontAjaxResponse())->setContent(array());
}
private function newEditDialog() {
return $this->newDialog()
->addHiddenInput('contextPHID', $this->contextPHID)
->addHiddenInput('panelKey', $this->panelKey)
->addHiddenInput('columnKey', $this->columnKey);
}
}

View file

@ -20,7 +20,7 @@ final class PhabricatorDashboardArchiveController
return new Aphront404Response();
}
$view_uri = $this->getApplicationURI('manage/'.$dashboard->getID().'/');
$view_uri = $dashboard->getURI();
if ($request->isFormPost()) {
if ($dashboard->isArchived()) {
@ -32,7 +32,8 @@ final class PhabricatorDashboardArchiveController
$xactions = array();
$xactions[] = id(new PhabricatorDashboardTransaction())
->setTransactionType(PhabricatorDashboardTransaction::TYPE_STATUS)
->setTransactionType(
PhabricatorDashboardStatusTransaction::TRANSACTIONTYPE)
->setNewValue($new_status);
id(new PhabricatorDashboardTransactionEditor())

View file

@ -0,0 +1,12 @@
<?php
final class PhabricatorDashboardEditController
extends PhabricatorDashboardController {
public function handleRequest(AphrontRequest $request) {
return id(new PhabricatorDashboardEditEngine())
->setController($this)
->buildResponse();
}
}

View file

@ -0,0 +1,75 @@
<?php
final class PhabricatorDashboardInstallController
extends PhabricatorDashboardController {
private $dashboard;
public function setDashboard(PhabricatorDashboard $dashboard) {
$this->dashboard = $dashboard;
return $this;
}
public function getDashboard() {
return $this->dashboard;
}
public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer();
$id = $request->getURIData('id');
$dashboard = id(new PhabricatorDashboardQuery())
->setViewer($viewer)
->withIDs(array($id))
->executeOne();
if (!$dashboard) {
return new Aphront404Response();
}
$this->setDashboard($dashboard);
$cancel_uri = $dashboard->getURI();
$workflow_key = $request->getURIData('workflowKey');
$workflows = PhabricatorDashboardInstallWorkflow::getAllWorkflows();
if (!isset($workflows[$workflow_key])) {
return $this->newWorkflowDialog($dashboard, $workflows);
}
return id(clone $workflows[$workflow_key])
->setRequest($request)
->setViewer($viewer)
->setDashboard($dashboard)
->setMode($request->getURIData('modeKey'))
->handleRequest($request);
}
private function newWorkflowDialog(
PhabricatorDashboard $dashboard,
array $workflows) {
$viewer = $this->getViewer();
$cancel_uri = $dashboard->getURI();
$menu = id(new PHUIObjectItemListView())
->setViewer($viewer)
->setFlush(true)
->setBig(true);
foreach ($workflows as $key => $workflow) {
$item = $workflow->getWorkflowMenuItem();
$item_href = urisprintf('install/%d/%s/', $dashboard->getID(), $key);
$item_href = $this->getApplicationURI($item_href);
$item->setHref($item_href);
$menu->addItem($item);
}
return $this->newDialog()
->setTitle(pht('Add Dashboard to Menu'))
->setWidth(AphrontDialogView::WIDTH_FORM)
->appendChild($menu)
->addCancelButton($cancel_uri);
}
}

View file

@ -0,0 +1,202 @@
<?php
final class PhabricatorDashboardViewController
extends PhabricatorDashboardProfileController {
public function shouldAllowPublic() {
return true;
}
public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer();
$id = $request->getURIData('id');
$dashboard = id(new PhabricatorDashboardQuery())
->setViewer($viewer)
->withIDs(array($id))
->executeOne();
if (!$dashboard) {
return new Aphront404Response();
}
$this->setDashboard($dashboard);
$can_edit = PhabricatorPolicyFilter::hasCapability(
$viewer,
$dashboard,
PhabricatorPolicyCapability::CAN_EDIT);
$title = $dashboard->getName();
$crumbs = $this->buildApplicationCrumbs();
$header = $this->buildHeaderView();
$curtain = $this->buildCurtainView($dashboard);
$usage_box = $this->newUsageView($dashboard);
$timeline = $this->buildTransactionTimeline(
$dashboard,
new PhabricatorDashboardTransactionQuery());
$timeline->setShouldTerminate(true);
$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);
$view = id(new PHUITwoColumnView())
->setHeader($header)
->setCurtain($curtain)
->setMainColumn(
array(
$dashboard_box,
$usage_box,
$timeline,
));
return $this->newPage()
->setTitle($title)
->setCrumbs($crumbs)
->appendChild($view);
}
private function buildCurtainView(PhabricatorDashboard $dashboard) {
$viewer = $this->getViewer();
$id = $dashboard->getID();
$curtain = $this->newCurtainView($dashboard);
$can_edit = PhabricatorPolicyFilter::hasCapability(
$viewer,
$dashboard,
PhabricatorPolicyCapability::CAN_EDIT);
$curtain->addAction(
id(new PhabricatorActionView())
->setName(pht('Edit Dashboard'))
->setIcon('fa-pencil')
->setHref($this->getApplicationURI("edit/{$id}/"))
->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(
id(new PhabricatorActionView())
->setName(pht('Activate Dashboard'))
->setIcon('fa-check')
->setHref($this->getApplicationURI("archive/{$id}/"))
->setDisabled(!$can_edit)
->setWorkflow(true));
} else {
$curtain->addAction(
id(new PhabricatorActionView())
->setName(pht('Archive Dashboard'))
->setIcon('fa-ban')
->setHref($this->getApplicationURI("archive/{$id}/"))
->setDisabled(!$can_edit)
->setWorkflow(true));
}
return $curtain;
}
private function newUsageView(PhabricatorDashboard $dashboard) {
$viewer = $this->getViewer();
$custom_phids = array();
if ($viewer->getPHID()) {
$custom_phids[] = $viewer->getPHID();
}
$items = id(new PhabricatorProfileMenuItemConfigurationQuery())
->setViewer($viewer)
->withAffectedObjectPHIDs(
array(
$dashboard->getPHID(),
))
->withCustomPHIDs($custom_phids, $include_global = true)
->execute();
$handle_phids = array();
foreach ($items as $item) {
$handle_phids[] = $item->getProfilePHID();
$custom_phid = $item->getCustomPHID();
if ($custom_phid) {
$handle_phids[] = $custom_phid;
}
}
if ($handle_phids) {
$handles = $viewer->loadHandles($handle_phids);
} else {
$handles = array();
}
$items = msortv($items, 'newUsageSortVector');
$rows = array();
foreach ($items as $item) {
$profile_phid = $item->getProfilePHID();
$custom_phid = $item->getCustomPHID();
$profile = $handles[$profile_phid]->renderLink();
$profile_icon = $handles[$profile_phid]->getIcon();
if ($custom_phid) {
$custom = $handles[$custom_phid]->renderLink();
} else {
$custom = pht('Global');
}
$type = $item->getProfileMenuTypeDescription();
$rows[] = array(
id(new PHUIIconView())->setIcon($profile_icon),
$type,
$profile,
$custom,
);
}
$usage_table = id(new AphrontTableView($rows))
->setNoDataString(
pht('This dashboard has not been added to any menus.'))
->setHeaders(
array(
null,
pht('Type'),
pht('Menu'),
pht('Global/Personal'),
))
->setColumnClasses(
array(
'center',
null,
'pri',
'wide',
));
$header_view = id(new PHUIHeaderView())
->setHeader(pht('Dashboard Used By'));
$usage_box = id(new PHUIObjectBoxView())
->setTable($usage_table)
->setHeader($header_view);
return $usage_box;
}
}

View file

@ -25,7 +25,8 @@ final class PhabricatorDashboardPanelArchiveController
if ($request->isFormPost()) {
$xactions = array();
$xactions[] = id(new PhabricatorDashboardPanelTransaction())
->setTransactionType(PhabricatorDashboardPanelTransaction::TYPE_ARCHIVE)
->setTransactionType(
PhabricatorDashboardPanelStatusTransaction::TRANSACTIONTYPE)
->setNewValue((int)!$panel->getIsArchived());
id(new PhabricatorDashboardPanelTransactionEditor())

View file

@ -0,0 +1,104 @@
<?php
final class PhabricatorDashboardPanelEditController
extends PhabricatorDashboardController {
public function handleRequest(AphrontRequest $request) {
$viewer = $this->getViewer();
$engine = id(new PhabricatorDashboardPanelEditEngine())
->setController($this);
// We can create or edit a panel in the context of a dashboard or
// container panel, like a tab panel. If we started this flow on some
// container object, we want to return to that container when we're done
// editing.
$context_phid = $request->getStr('contextPHID');
if (strlen($context_phid)) {
$context = id(new PhabricatorObjectQuery())
->setViewer($viewer)
->withPHIDs(array($context_phid))
->requireCapabilities(
array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT,
))
->executeOne();
if (!$context) {
return new Aphront404Response();
}
if (!($context instanceof PhabricatorDashboardPanelContainerInterface)) {
return new Aphront404Response();
}
$engine
->setContextObject($context)
->addContextParameter('contextPHID', $context_phid);
} else {
$context = null;
}
$id = $request->getURIData('id');
if (!$id) {
$column_key = $request->getStr('columnKey');
if ($context) {
$cancel_uri = $context->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('columnKey', $column_key)
->setPanelType($panel_type)
->setColumnKey($column_key);
}
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);
}
}

View file

@ -43,7 +43,7 @@ final class PhabricatorDashboardPanelListController
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 @@ final class PhabricatorDashboardPanelListController
$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();

View file

@ -31,14 +31,28 @@ final class PhabricatorDashboardPanelRenderController
$parent_phids = array();
}
$rendered_panel = id(new PhabricatorDashboardPanelRenderingEngine())
$engine = id(new PhabricatorDashboardPanelRenderingEngine())
->setViewer($viewer)
->setPanel($panel)
->setPanelPHID($panel->getPHID())
->setParentPanelPHIDs($parent_phids)
->setMovable($request->getBool('movable'))
->setHeaderMode($request->getStr('headerMode'))
->setDashboardID($request->getInt('dashboardID'))
->renderPanel();
->setPanelKey($request->getStr('panelKey'));
$context_phid = $request->getStr('contextPHID');
if ($context_phid) {
$context = id(new PhabricatorObjectQuery())
->setViewer($viewer)
->withPHIDs(array($context_phid))
->executeOne();
if (!$context) {
return new Aphront404Response();
}
$engine->setContextObject($context);
}
$rendered_panel = $engine->renderPanel();
if ($request->isAjax()) {
return id(new AphrontAjaxResponse())

View file

@ -0,0 +1,354 @@
<?php
final class PhabricatorDashboardPanelTabsController
extends PhabricatorDashboardController {
private $contextObject;
private function setContextObject($context_object) {
$this->contextObject = $context_object;
return $this;
}
private function getContextObject() {
return $this->contextObject;
}
public function handleRequest(AphrontRequest $request) {
$viewer = $this->getViewer();
$panel = id(new PhabricatorDashboardPanelQuery())
->setViewer($viewer)
->withIDs(array($request->getURIData('id')))
->requireCapabilities(
array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT,
))
->executeOne();
if (!$panel) {
return new Aphront404Response();
}
$tabs_type = id(new PhabricatorDashboardTabsPanelType())
->getPanelTypeKey();
// This controller may only be used to edit tab panels.
$panel_type = $panel->getPanelType();
if ($panel_type !== $tabs_type) {
return new Aphront404Response();
}
$op = $request->getURIData('op');
$after = $request->getStr('after');
if (!strlen($after)) {
$after = null;
}
$target = $request->getStr('target');
if (!strlen($target)) {
$target = null;
}
$impl = $panel->getImplementation();
$config = $impl->getPanelConfiguration($panel);
$cancel_uri = $panel->getURI();
if ($after !== null) {
$found = false;
foreach ($config as $key => $spec) {
if ((string)$key === $after) {
$found = true;
break;
}
}
if (!$found) {
return $this->newDialog()
->setTitle(pht('Adjacent Tab Not Found'))
->appendParagraph(
pht(
'Adjacent tab ("%s") was not found on this panel. It may have '.
'been removed.',
$after))
->addCancelButton($cancel_uri);
}
}
if ($target !== null) {
$found = false;
foreach ($config as $key => $spec) {
if ((string)$key === $target) {
$found = true;
break;
}
}
if (!$found) {
return $this->newDialog()
->setTitle(pht('Target Tab Not Found'))
->appendParagraph(
pht(
'Target tab ("%s") was not found on this panel. It may have '.
'been removed.',
$target))
->addCancelButton($cancel_uri);
}
}
// Tab panels may be edited from the panel page, or from the context of
// a dashboard. If we're editing from a dashboard, we want to redirect
// back to the dashboard after making changes.
$context_phid = $request->getStr('contextPHID');
$context = null;
if (strlen($context_phid)) {
$context = id(new PhabricatorObjectQuery())
->setViewer($viewer)
->withPHIDs(array($context_phid))
->executeOne();
if (!$context) {
return new Aphront404Response();
}
switch (phid_get_type($context_phid)) {
case PhabricatorDashboardDashboardPHIDType::TYPECONST:
$cancel_uri = $context->getURI();
break;
case PhabricatorDashboardPanelPHIDType::TYPECONST:
$cancel_uri = $context->getURI();
break;
default:
return $this->newDialog()
->setTitle(pht('Context Object Unsupported'))
->appendParagraph(
pht(
'Context object ("%s") has unsupported type. Panels should '.
'be rendered from the context of a dashboard or another '.
'panel.',
$context_phid))
->addCancelButton($cancel_uri);
}
$this->setContextObject($context);
}
switch ($op) {
case 'add':
return $this->handleAddOperation($panel, $after, $cancel_uri);
case 'remove':
return $this->handleRemoveOperation($panel, $target, $cancel_uri);
case 'move':
break;
case 'rename':
return $this->handleRenameOperation($panel, $target, $cancel_uri);
}
}
private function handleAddOperation(
PhabricatorDashboardPanel $panel,
$after,
$cancel_uri) {
$request = $this->getRequest();
$viewer = $this->getViewer();
$panel_phid = null;
$errors = array();
if ($request->isFormPost()) {
$panel_phid = $request->getArr('panelPHID');
$panel_phid = head($panel_phid);
$add_panel = id(new PhabricatorDashboardPanelQuery())
->setViewer($viewer)
->withPHIDs(array($panel_phid))
->executeOne();
if (!$add_panel) {
$errors[] = pht('You must select a valid panel.');
}
if (!$errors) {
$add_panel_config = array(
'name' => null,
'panelID' => $add_panel->getID(),
);
$add_panel_key = Filesystem::readRandomCharacters(12);
$impl = $panel->getImplementation();
$old_config = $impl->getPanelConfiguration($panel);
$new_config = array();
if ($after === null) {
$new_config = $old_config;
$new_config[] = $add_panel_config;
} else {
foreach ($old_config as $key => $value) {
$new_config[$key] = $value;
if ((string)$key === $after) {
$new_config[$add_panel_key] = $add_panel_config;
}
}
}
$xactions = array();
$xactions[] = $panel->getApplicationTransactionTemplate()
->setTransactionType(
PhabricatorDashboardTabsPanelTabsTransaction::TRANSACTIONTYPE)
->setNewValue($new_config);
$editor = id(new PhabricatorDashboardPanelTransactionEditor())
->setContentSourceFromRequest($request)
->setActor($viewer)
->setContinueOnNoEffect(true)
->setContinueOnMissingFields(true);
$editor->applyTransactions($panel, $xactions);
return id(new AphrontRedirectResponse())->setURI($cancel_uri);
}
}
if ($panel_phid) {
$v_panel = array($panel_phid);
} else {
$v_panel = array();
}
$form = id(new AphrontFormView())
->setViewer($viewer)
->appendControl(
id(new AphrontFormTokenizerControl())
->setDatasource(new PhabricatorDashboardPanelDatasource())
->setLimit(1)
->setName('panelPHID')
->setLabel(pht('Panel'))
->setValue($v_panel));
return $this->newEditDialog()
->setTitle(pht('Choose Dashboard Panel'))
->setErrors($errors)
->addHiddenInput('after', $after)
->appendForm($form)
->addCancelButton($cancel_uri)
->addSubmitButton(pht('Add Panel'));
}
private function handleRemoveOperation(
PhabricatorDashboardPanel $panel,
$target,
$cancel_uri) {
$request = $this->getRequest();
$viewer = $this->getViewer();
$panel_phid = null;
$errors = array();
if ($request->isFormPost()) {
$impl = $panel->getImplementation();
$old_config = $impl->getPanelConfiguration($panel);
$new_config = $this->removePanel($old_config, $target);
$this->writePanelConfig($panel, $new_config);
return id(new AphrontRedirectResponse())->setURI($cancel_uri);
}
return $this->newEditDialog()
->setTitle(pht('Remove tab?'))
->addHiddenInput('target', $target)
->appendParagraph(pht('Really remove this tab?'))
->addCancelButton($cancel_uri)
->addSubmitButton(pht('Remove Tab'));
}
private function handleRenameOperation(
PhabricatorDashboardPanel $panel,
$target,
$cancel_uri) {
$request = $this->getRequest();
$viewer = $this->getViewer();
$impl = $panel->getImplementation();
$old_config = $impl->getPanelConfiguration($panel);
$spec = $old_config[$target];
$name = idx($spec, 'name');
if ($request->isFormPost()) {
$name = $request->getStr('name');
$new_config = $this->renamePanel($old_config, $target, $name);
$this->writePanelConfig($panel, $new_config);
return id(new AphrontRedirectResponse())->setURI($cancel_uri);
}
$form = id(new AphrontFormView())
->setViewer($viewer)
->appendControl(
id(new AphrontFormTextControl())
->setValue($name)
->setName('name')
->setLabel(pht('Tab Name')));
return $this->newEditDialog()
->setTitle(pht('Rename Panel'))
->addHiddenInput('target', $target)
->appendForm($form)
->addCancelButton($cancel_uri)
->addSubmitButton(pht('Rename Tab'));
}
private function writePanelConfig(
PhabricatorDashboardPanel $panel,
array $config) {
$request = $this->getRequest();
$viewer = $this->getViewer();
$xactions = array();
$xactions[] = $panel->getApplicationTransactionTemplate()
->setTransactionType(
PhabricatorDashboardTabsPanelTabsTransaction::TRANSACTIONTYPE)
->setNewValue($config);
$editor = id(new PhabricatorDashboardPanelTransactionEditor())
->setContentSourceFromRequest($request)
->setActor($viewer)
->setContinueOnNoEffect(true)
->setContinueOnMissingFields(true);
return $editor->applyTransactions($panel, $xactions);
}
private function removePanel(array $config, $target) {
$result = array();
foreach ($config as $key => $panel_spec) {
if ((string)$key === $target) {
continue;
}
$result[$key] = $panel_spec;
}
return $result;
}
private function renamePanel(array $config, $target, $name) {
$config[$target]['name'] = $name;
return $config;
}
protected function newEditDialog() {
$dialog = $this->newDialog()
->setWidth(AphrontDialogView::WIDTH_FORM);
$context = $this->getContextObject();
if ($context) {
$dialog->addHiddenInput('contextPHID', $context->getPHID());
}
return $dialog;
}
}

View file

@ -19,6 +19,11 @@ final class PhabricatorDashboardPanelViewController
return new Aphront404Response();
}
$can_edit = PhabricatorPolicyFilter::hasCapability(
$viewer,
$panel,
PhabricatorPolicyCapability::CAN_EDIT);
$title = $panel->getMonogram().' '.$panel->getName();
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb(
@ -29,17 +34,21 @@ final class PhabricatorDashboardPanelViewController
$header = $this->buildHeaderView($panel);
$curtain = $this->buildCurtainView($panel);
$properties = $this->buildPropertyView($panel);
$usage_box = $this->newUsageView($panel);
$timeline = $this->buildTransactionTimeline(
$panel,
new PhabricatorDashboardPanelTransactionQuery());
$timeline->setShouldTerminate(true);
$rendered_panel = id(new PhabricatorDashboardPanelRenderingEngine())
->setViewer($viewer)
->setPanel($panel)
->setContextObject($panel)
->setPanelPHID($panel->getPHID())
->setParentPanelPHIDs(array())
->setEditMode(true)
->renderPanel();
$preview = id(new PHUIBoxView())
@ -50,10 +59,10 @@ final class PhabricatorDashboardPanelViewController
->setHeader($header)
->setCurtain($curtain)
->setMainColumn(array(
$properties,
$rendered_panel,
$usage_box,
$timeline,
))
->setFooter($rendered_panel);
));
return $this->newPage()
->setTitle($title)
@ -65,18 +74,11 @@ final class PhabricatorDashboardPanelViewController
$viewer = $this->getViewer();
$id = $panel->getID();
$button = id(new PHUIButtonView())
->setTag('a')
->setText(pht('View Panel'))
->setIcon('fa-columns')
->setHref($this->getApplicationURI("panel/render/{$id}/"));
$header = id(new PHUIHeaderView())
->setUser($viewer)
->setHeader($panel->getName())
->setPolicyObject($panel)
->setHeaderIcon('fa-columns')
->addActionLink($button);
->setHeaderIcon('fa-window-maximize');
if (!$panel->getIsArchived()) {
$header->setStatus('fa-check', 'bluegrey', pht('Active'));
@ -124,51 +126,51 @@ final class PhabricatorDashboardPanelViewController
return $curtain;
}
private function buildPropertyView(PhabricatorDashboardPanel $panel) {
private function newUsageView(PhabricatorDashboardPanel $panel) {
$viewer = $this->getViewer();
$properties = id(new PHUIPropertyListView())
->setUser($viewer);
$object_phids = PhabricatorEdgeQuery::loadDestinationPHIDs(
$panel->getPHID(),
PhabricatorDashboardPanelUsedByObjectEdgeType::EDGECONST);
$descriptions = PhabricatorPolicyQuery::renderPolicyDescriptions(
$viewer,
$panel);
$panel_type = $panel->getImplementation();
if ($panel_type) {
$type_name = $panel_type->getPanelTypeName();
if ($object_phids) {
$handles = $viewer->loadHandles($object_phids);
} else {
$type_name = phutil_tag(
'em',
array(),
nonempty($panel->getPanelType(), pht('null')));
$handles = array();
}
$properties->addProperty(
pht('Panel Type'),
$type_name);
$rows = array();
foreach ($object_phids as $object_phid) {
$handle = $handles[$object_phid];
$properties->addProperty(
pht('Editable By'),
$descriptions[PhabricatorPolicyCapability::CAN_EDIT]);
$icon = $handle->getIcon();
$dashboard_phids = PhabricatorEdgeQuery::loadDestinationPHIDs(
$panel->getPHID(),
PhabricatorDashboardPanelHasDashboardEdgeType::EDGECONST);
$rows[] = array(
id(new PHUIIconView())->setIcon($icon),
$handle->getTypeName(),
$handle->renderLink(),
);
}
$does_not_appear = pht(
'This panel does not appear on any dashboards.');
$usage_table = id(new AphrontTableView($rows))
->setNoDataString(
pht(
'This panel is not used on any dashboard or inside any other '.
'panel container.'))
->setColumnClasses(
array(
'center',
'',
'pri wide',
));
$properties->addProperty(
pht('Appears On'),
$dashboard_phids
? $viewer->renderHandleList($dashboard_phids)
: phutil_tag('em', array(), $does_not_appear));
$header_view = id(new PHUIHeaderView())
->setHeader(pht('Panel Used By'));
return id(new PHUIObjectBoxView())
->setHeaderText(pht('Details'))
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->addPropertyList($properties);
$usage_box = id(new PHUIObjectBoxView())
->setTable($usage_table)
->setHeader($header_view);
return $usage_box;
}
}

View file

@ -0,0 +1,18 @@
<?php
abstract class PhabricatorDashboardPortalController
extends PhabricatorDashboardController {
protected function buildApplicationCrumbs() {
$crumbs = new PHUICrumbsView();
$crumbs->addCrumb(
id(new PHUICrumbView())
->setHref('/portal/')
->setName(pht('Portals'))
->setIcon('fa-compass'));
return $crumbs;
}
}

View file

@ -0,0 +1,12 @@
<?php
final class PhabricatorDashboardPortalEditController
extends PhabricatorDashboardPortalController {
public function handleRequest(AphrontRequest $request) {
return id(new PhabricatorDashboardPortalEditEngine())
->setController($this)
->buildResponse();
}
}

View file

@ -0,0 +1,26 @@
<?php
final class PhabricatorDashboardPortalListController
extends PhabricatorDashboardPortalController {
public function shouldAllowPublic() {
return true;
}
public function handleRequest(AphrontRequest $request) {
return id(new PhabricatorDashboardPortalSearchEngine())
->setController($this)
->buildResponse();
}
protected function buildApplicationCrumbs() {
$crumbs = parent::buildApplicationCrumbs();
id(new PhabricatorDashboardPortalEditEngine())
->setViewer($this->getViewer())
->addActionToCrumbs($crumbs);
return $crumbs;
}
}

View file

@ -0,0 +1,59 @@
<?php
final class PhabricatorDashboardPortalViewController
extends PhabricatorDashboardPortalController {
private $portal;
public function setPortal(PhabricatorDashboardPortal $portal) {
$this->portal = $portal;
return $this;
}
public function getPortal() {
return $this->portal;
}
public function shouldAllowPublic() {
return true;
}
public function handleRequest(AphrontRequest $request) {
$viewer = $this->getViewer();
$id = $request->getURIData('portalID');
$portal = id(new PhabricatorDashboardPortalQuery())
->setViewer($viewer)
->withIDs(array($id))
->executeOne();
if (!$portal) {
return new Aphront404Response();
}
$this->setPortal($portal);
$engine = id(new PhabricatorDashboardPortalProfileMenuEngine())
->setProfileObject($portal)
->setController($this);
return $engine->buildResponse();
}
protected function buildApplicationCrumbs() {
$crumbs = parent::buildApplicationCrumbs();
$portal = $this->getPortal();
if ($portal) {
$crumbs->addTextCrumb($portal->getName(), $portal->getURI());
}
return $crumbs;
}
public function newTimelineView() {
return $this->buildTransactionTimeline(
$this->getPortal(),
new PhabricatorDashboardPortalTransactionQuery());
}
}

View file

@ -1,47 +0,0 @@
<?php
final class PhabricatorDashboardPanelCoreCustomField
extends PhabricatorDashboardPanelCustomField
implements PhabricatorStandardCustomFieldInterface {
public function getStandardCustomFieldNamespace() {
return 'dashboard:core';
}
public function createFields($object) {
if (!$object->getPanelType()) {
return array();
}
$impl = $object->requireImplementation();
$specs = $impl->getFieldSpecifications();
return PhabricatorStandardCustomField::buildStandardFields($this, $specs);
}
public function shouldUseStorage() {
return false;
}
public function readValueFromObject(PhabricatorCustomFieldInterface $object) {
$key = $this->getProxy()->getRawStandardFieldKey();
$this->setValueFromStorage($object->getProperty($key));
$this->didSetValueFromStorage();
}
public function applyApplicationTransactionInternalEffects(
PhabricatorApplicationTransaction $xaction) {
$object = $this->getObject();
$key = $this->getProxy()->getRawStandardFieldKey();
$this->setValueFromApplicationTransactions($xaction->getNewValue());
$value = $this->getValueForStorage();
$object->setProperty($key, $value);
}
public function applyApplicationTransactionExternalEffects(
PhabricatorApplicationTransaction $xaction) {
return;
}
}

View file

@ -1,4 +0,0 @@
<?php
abstract class PhabricatorDashboardPanelCustomField
extends PhabricatorCustomField {}

View file

@ -1,114 +0,0 @@
<?php
final class PhabricatorDashboardPanelTabsCustomField
extends PhabricatorStandardCustomField {
public function getFieldType() {
return 'dashboard.tabs';
}
public function shouldAppearInApplicationSearch() {
return false;
}
public function readValueFromRequest(AphrontRequest $request) {
$value = array();
$names = $request->getArr($this->getFieldKey().'_name');
$panel_ids = $request->getArr($this->getFieldKey().'_panelID');
$panels = array();
foreach ($panel_ids as $panel_id) {
$panels[] = $panel_id[0];
}
foreach ($names as $idx => $name) {
$panel_id = idx($panels, $idx);
if (strlen($name) && $panel_id) {
$value[] = array(
'name' => $name,
'panelID' => $panel_id,
);
}
}
$this->setFieldValue($value);
}
public function getApplicationTransactionTitle(
PhabricatorApplicationTransaction $xaction) {
$author_phid = $xaction->getAuthorPHID();
$old = $xaction->getOldValue();
$new = $xaction->getNewValue();
$new_tabs = array();
if ($new) {
foreach ($new as $new_tab) {
$new_tabs[] = $new_tab['name'];
}
$new_tabs = implode(' | ', $new_tabs);
}
$old_tabs = array();
if ($old) {
foreach ($old as $old_tab) {
$old_tabs[] = $old_tab['name'];
}
$old_tabs = implode(' | ', $old_tabs);
}
if (!$old) {
// In case someone makes a tab panel with no tabs.
if ($new) {
return pht(
'%s set the tabs to "%s".',
$xaction->renderHandleLink($author_phid),
$new_tabs);
}
} else if (!$new) {
return pht(
'%s removed tabs.',
$xaction->renderHandleLink($author_phid));
} else {
return pht(
'%s changed the tabs from "%s" to "%s".',
$xaction->renderHandleLink($author_phid),
$old_tabs,
$new_tabs);
}
}
public function renderEditControl(array $handles) {
// NOTE: This includes archived panels so we don't mutate the tabs
// when saving a tab panel that includes archived panels. This whole UI is
// hopefully temporary anyway.
$value = $this->getFieldValue();
if (!is_array($value)) {
$value = array();
}
$out = array();
for ($ii = 1; $ii <= 6; $ii++) {
$tab = idx($value, ($ii - 1), array());
$panel = idx($tab, 'panelID', null);
$panel_id = array();
if ($panel) {
$panel_id[] = $panel;
}
$out[] = id(new AphrontFormTextControl())
->setName($this->getFieldKey().'_name[]')
->setValue(idx($tab, 'name'))
->setLabel(pht('Tab %d Name', $ii));
$out[] = id(new AphrontFormTokenizerControl())
->setUser($this->getViewer())
->setDatasource(new PhabricatorDashboardPanelDatasource())
->setName($this->getFieldKey().'_panelID[]')
->setValue($panel_id)
->setLimit(1)
->setLabel(pht('Tab %d Panel', $ii));
}
return $out;
}
}

View file

@ -1,103 +0,0 @@
<?php
final class PhabricatorDashboardDashboardHasPanelEdgeType
extends PhabricatorEdgeType {
const EDGECONST = 45;
public function getInverseEdgeConstant() {
return PhabricatorDashboardPanelHasDashboardEdgeType::EDGECONST;
}
public function shouldWriteInverseTransactions() {
return true;
}
public function getTransactionAddString(
$actor,
$add_count,
$add_edges) {
return pht(
'%s added %s panel(s): %s.',
$actor,
$add_count,
$add_edges);
}
public function getTransactionRemoveString(
$actor,
$rem_count,
$rem_edges) {
return pht(
'%s removed %s panel(s): %s.',
$actor,
$rem_count,
$rem_edges);
}
public function getTransactionEditString(
$actor,
$total_count,
$add_count,
$add_edges,
$rem_count,
$rem_edges) {
return pht(
'%s edited panel(s), added %s: %s; removed %s: %s.',
$actor,
$add_count,
$add_edges,
$rem_count,
$rem_edges);
}
public function getFeedAddString(
$actor,
$object,
$add_count,
$add_edges) {
return pht(
'%s added %s panel(s) for %s: %s.',
$actor,
$add_count,
$object,
$add_edges);
}
public function getFeedRemoveString(
$actor,
$object,
$rem_count,
$rem_edges) {
return pht(
'%s removed %s panel(s) for %s: %s.',
$actor,
$rem_count,
$object,
$rem_edges);
}
public function getFeedEditString(
$actor,
$object,
$total_count,
$add_count,
$add_edges,
$rem_count,
$rem_edges) {
return pht(
'%s edited panel(s) for %s, added %s: %s; removed %s: %s.',
$actor,
$object,
$add_count,
$add_edges,
$rem_count,
$rem_edges);
}
}

View file

@ -1,103 +0,0 @@
<?php
final class PhabricatorDashboardPanelHasDashboardEdgeType
extends PhabricatorEdgeType {
const EDGECONST = 46;
public function getInverseEdgeConstant() {
return PhabricatorDashboardDashboardHasPanelEdgeType::EDGECONST;
}
public function shouldWriteInverseTransactions() {
return true;
}
public function getTransactionAddString(
$actor,
$add_count,
$add_edges) {
return pht(
'%s added %s dashboard(s): %s.',
$actor,
$add_count,
$add_edges);
}
public function getTransactionRemoveString(
$actor,
$rem_count,
$rem_edges) {
return pht(
'%s removed %s dashboard(s): %s.',
$actor,
$rem_count,
$rem_edges);
}
public function getTransactionEditString(
$actor,
$total_count,
$add_count,
$add_edges,
$rem_count,
$rem_edges) {
return pht(
'%s edited dashboard(s), added %s: %s; removed %s: %s.',
$actor,
$add_count,
$add_edges,
$rem_count,
$rem_edges);
}
public function getFeedAddString(
$actor,
$object,
$add_count,
$add_edges) {
return pht(
'%s added %s dashboard(s) for %s: %s.',
$actor,
$add_count,
$object,
$add_edges);
}
public function getFeedRemoveString(
$actor,
$object,
$rem_count,
$rem_edges) {
return pht(
'%s removed %s dashboard(s) for %s: %s.',
$actor,
$rem_count,
$object,
$rem_edges);
}
public function getFeedEditString(
$actor,
$object,
$total_count,
$add_count,
$add_edges,
$rem_count,
$rem_edges) {
return pht(
'%s edited dashboard(s) for %s, added %s: %s; removed %s: %s.',
$actor,
$object,
$add_count,
$add_edges,
$rem_count,
$rem_edges);
}
}

View file

@ -1,17 +1,11 @@
<?php
final class PhabricatorDashboardPanelSearchApplicationCustomField
extends PhabricatorStandardCustomField {
final class PhabricatorDashboardQueryPanelApplicationEditField
extends PhabricatorEditField {
public function getFieldType() {
return 'search.application';
}
private $controlID;
public function shouldAppearInApplicationSearch() {
return false;
}
public function renderEditControl(array $handles) {
protected function newControl() {
$engines = id(new PhutilClassMapQuery())
->setAncestorClass('PhabricatorApplicationSearchEngine')
->setFilterMethod('canUseInPanelContext')
@ -31,7 +25,7 @@ final class PhabricatorDashboardPanelSearchApplicationCustomField
$options = array();
$value = $this->getFieldValue();
$value = $this->getValueForControl();
if (strlen($value) && empty($engines[$value])) {
$options[$value] = $value;
}
@ -42,12 +36,24 @@ final class PhabricatorDashboardPanelSearchApplicationCustomField
}
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();
}
}

View file

@ -1,23 +1,26 @@
<?php
final class PhabricatorDashboardPanelSearchQueryCustomField
extends PhabricatorStandardCustomField {
final class PhabricatorDashboardQueryPanelQueryEditField
extends PhabricatorEditField {
public function getFieldType() {
return 'search.query';
private $applicationControlID;
public function setApplicationControlID($id) {
$this->applicationControlID = $id;
return $this;
}
public function shouldAppearInApplicationSearch() {
return false;
public function getApplicationControlID() {
return $this->applicationControlID;
}
public function renderEditControl(array $handles) {
protected function newControl() {
$engines = id(new PhutilClassMapQuery())
->setAncestorClass('PhabricatorApplicationSearchEngine')
->setFilterMethod('canUseInPanelContext')
->execute();
$value = $this->getFieldValue();
$value = $this->getValueForControl();
$queries = array();
$seen = false;
@ -43,12 +46,14 @@ final class PhabricatorDashboardPanelSearchQueryCustomField
$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 @@ final class PhabricatorDashboardPanelSearchQueryCustomField
));
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();
}
}

View file

@ -0,0 +1,108 @@
<?php
final class PhabricatorDashboardEditEngine
extends PhabricatorEditEngine {
const ENGINECONST = 'dashboard';
public function isEngineConfigurable() {
return false;
}
public function getEngineName() {
return pht('Dashboards');
}
public function getSummaryHeader() {
return pht('Edit Dashboards');
}
public function getSummaryText() {
return pht('This engine is used to modify dashboards.');
}
public function getEngineApplicationClass() {
return 'PhabricatorDashboardApplication';
}
protected function newEditableObject() {
$viewer = $this->getViewer();
return PhabricatorDashboard::initializeNewDashboard($viewer);
}
protected function newObjectQuery() {
return new PhabricatorDashboardQuery();
}
protected function getObjectCreateTitleText($object) {
return pht('Create Dashboard');
}
protected function getObjectCreateButtonText($object) {
return pht('Create Dashboard');
}
protected function getObjectCreateCancelURI($object) {
return '/dashboard/';
}
protected function getObjectEditTitleText($object) {
return pht('Edit Dashboard: %s', $object->getName());
}
protected function getObjectEditShortText($object) {
return pht('Edit Dashboard');
}
protected function getObjectCreateShortText() {
return pht('Create Dashboard');
}
protected function getObjectName() {
return pht('Dashboard');
}
protected function getObjectViewURI($object) {
return $object->getURI();
}
protected function buildCustomEditFields($object) {
$layout_options = PhabricatorDashboardLayoutMode::getLayoutModeMap();
$fields = array(
id(new PhabricatorTextEditField())
->setKey('name')
->setLabel(pht('Name'))
->setDescription(pht('Name of the dashboard.'))
->setConduitDescription(pht('Rename the dashboard.'))
->setConduitTypeDescription(pht('New dashboard name.'))
->setTransactionType(
PhabricatorDashboardNameTransaction::TRANSACTIONTYPE)
->setIsRequired(true)
->setValue($object->getName()),
id(new PhabricatorIconSetEditField())
->setKey('icon')
->setLabel(pht('Icon'))
->setTransactionType(
PhabricatorDashboardIconTransaction::TRANSACTIONTYPE)
->setIconSet(new PhabricatorDashboardIconSet())
->setDescription(pht('Dashboard icon.'))
->setConduitDescription(pht('Change the dashboard icon.'))
->setConduitTypeDescription(pht('New dashboard icon.'))
->setValue($object->getIcon()),
id(new PhabricatorSelectEditField())
->setKey('layout')
->setLabel(pht('Layout'))
->setDescription(pht('Dashboard layout mode.'))
->setConduitDescription(pht('Change the dashboard layout mode.'))
->setConduitTypeDescription(pht('New dashboard layout mode.'))
->setTransactionType(
PhabricatorDashboardLayoutTransaction::TRANSACTIONTYPE)
->setOptions($layout_options)
->setValue($object->getRawLayoutMode()),
);
return $fields;
}
}

View file

@ -6,6 +6,8 @@ final class PhabricatorDashboardPanelEditEngine
const ENGINECONST = 'dashboard.panel';
private $panelType;
private $contextObject;
private $columnKey;
public function setPanelType($panel_type) {
$this->panelType = $panel_type;
@ -16,6 +18,24 @@ final class PhabricatorDashboardPanelEditEngine
return $this->panelType;
}
public function setContextObject($context) {
$this->contextObject = $context;
return $this;
}
public function getContextObject() {
return $this->contextObject;
}
public function setColumnKey($column_key) {
$this->columnKey = $column_key;
return $this;
}
public function getColumnKey() {
return $this->columnKey;
}
public function isEngineConfigurable() {
return false;
}
@ -63,6 +83,33 @@ final class PhabricatorDashboardPanelEditEngine
return pht('Create Panel');
}
protected function getObjectCreateCancelURI($object) {
$context = $this->getContextObject();
if ($context) {
return $context->getURI();
}
return parent::getObjectCreateCancelURI($object);
}
public function getEffectiveObjectEditDoneURI($object) {
$context = $this->getContextObject();
if ($context) {
return $context->getURI();
}
return parent::getEffectiveObjectEditDoneURI($object);
}
protected function getObjectEditCancelURI($object) {
$context = $this->getContextObject();
if ($context) {
return $context->getURI();
}
return parent::getObjectEditCancelURI($object);
}
protected function getObjectEditTitleText($object) {
return pht('Edit Panel: %s', $object->getName());
}
@ -83,18 +130,58 @@ final class PhabricatorDashboardPanelEditEngine
return $object->getURI();
}
protected function didApplyTransactions($object, array $xactions) {
$context = $this->getContextObject();
if ($context instanceof PhabricatorDashboard) {
$viewer = $this->getViewer();
$controller = $this->getController();
$request = $controller->getRequest();
$dashboard = $context;
$xactions = array();
$ref_list = clone $dashboard->getPanelRefList();
$ref_list->newPanelRef($object, $this->getColumnKey());
$new_panels = $ref_list->toDictionary();
$xactions[] = $dashboard->getApplicationTransactionTemplate()
->setTransactionType(
PhabricatorDashboardPanelsTransaction::TRANSACTIONTYPE)
->setNewValue($new_panels);
$editor = $dashboard->getApplicationTransactionEditor()
->setActor($viewer)
->setContentSourceFromRequest($request)
->setContinueOnNoEffect(true)
->setContinueOnMissingFields(true);
$editor->applyTransactions($dashboard, $xactions);
}
}
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;
}
}

View file

@ -18,96 +18,11 @@ final class PhabricatorDashboardPanelTransactionEditor
$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 supportsSearch() {
return true;
}
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;
}
}

View file

@ -0,0 +1,87 @@
<?php
final class PhabricatorDashboardPortalEditEngine
extends PhabricatorEditEngine {
const ENGINECONST = 'portal';
public function isEngineConfigurable() {
return false;
}
public function getEngineName() {
return pht('Portals');
}
public function getSummaryHeader() {
return pht('Edit Portals');
}
public function getSummaryText() {
return pht('This engine is used to modify portals.');
}
public function getEngineApplicationClass() {
return 'PhabricatorDashboardApplication';
}
protected function newEditableObject() {
return PhabricatorDashboardPortal::initializeNewPortal();
}
protected function newObjectQuery() {
return new PhabricatorDashboardPortalQuery();
}
protected function getObjectCreateTitleText($object) {
return pht('Create Portal');
}
protected function getObjectCreateButtonText($object) {
return pht('Create Portal');
}
protected function getObjectEditTitleText($object) {
return pht('Edit Portal: %s', $object->getName());
}
protected function getObjectEditShortText($object) {
return pht('Edit Portal');
}
protected function getObjectCreateShortText() {
return pht('Create Portal');
}
protected function getObjectName() {
return pht('Portal');
}
protected function getObjectViewURI($object) {
if ($this->getIsCreate()) {
return $object->getURI();
} else {
return '/portal/view/'.$object->getID().'/view/manage/';
}
}
protected function getEditorURI() {
return '/portal/edit/';
}
protected function buildCustomEditFields($object) {
return array(
id(new PhabricatorTextEditField())
->setKey('name')
->setLabel(pht('Name'))
->setDescription(pht('Name of the portal.'))
->setConduitDescription(pht('Rename the portal.'))
->setConduitTypeDescription(pht('New portal name.'))
->setTransactionType(
PhabricatorDashboardPortalNameTransaction::TRANSACTIONTYPE)
->setIsRequired(true)
->setValue($object->getName()),
);
}
}

View file

@ -0,0 +1,35 @@
<?php
final class PhabricatorDashboardPortalEditor
extends PhabricatorApplicationTransactionEditor {
public function getEditorApplicationClass() {
return 'PhabricatorDashboardApplication';
}
public function getEditorObjectsDescription() {
return pht('Portals');
}
public function getCreateObjectTitle($author, $object) {
return pht('%s created this portal.', $author);
}
public function getCreateObjectTitleForFeed($author, $object) {
return pht('%s created %s.', $author, $object);
}
public function getTransactionTypes() {
$types = parent::getTransactionTypes();
$types[] = PhabricatorTransactions::TYPE_VIEW_POLICY;
$types[] = PhabricatorTransactions::TYPE_EDIT_POLICY;
return $types;
}
protected function supportsSearch() {
return true;
}
}

View file

@ -11,38 +11,6 @@ final class PhabricatorDashboardTransactionEditor
return pht('Dashboards');
}
public static function addPanelToDashboard(
PhabricatorUser $actor,
PhabricatorContentSource $content_source,
PhabricatorDashboardPanel $panel,
PhabricatorDashboard $dashboard,
$column) {
$xactions = array();
$xactions[] = id(new PhabricatorDashboardTransaction())
->setTransactionType(PhabricatorTransactions::TYPE_EDGE)
->setMetadataValue(
'edge:type',
PhabricatorDashboardDashboardHasPanelEdgeType::EDGECONST)
->setNewValue(
array(
'+' => array(
$panel->getPHID() => $panel->getPHID(),
),
));
$layout_config = $dashboard->getLayoutConfigObject();
$layout_config->setPanelLocation($column, $panel->getPHID());
$dashboard->setLayoutConfigFromObject($layout_config);
$editor = id(new PhabricatorDashboardTransactionEditor())
->setActor($actor)
->setContentSource($content_source)
->setContinueOnMissingFields(true)
->setContinueOnNoEffect(true)
->applyTransactions($dashboard, $xactions);
}
public function getTransactionTypes() {
$types = parent::getTransactionTypes();
@ -50,133 +18,11 @@ final class PhabricatorDashboardTransactionEditor
$types[] = PhabricatorTransactions::TYPE_EDIT_POLICY;
$types[] = PhabricatorTransactions::TYPE_EDGE;
$types[] = PhabricatorDashboardTransaction::TYPE_NAME;
$types[] = PhabricatorDashboardTransaction::TYPE_ICON;
$types[] = PhabricatorDashboardTransaction::TYPE_STATUS;
$types[] = PhabricatorDashboardTransaction::TYPE_LAYOUT_MODE;
return $types;
}
protected function getCustomTransactionOldValue(
PhabricatorLiskDAO $object,
PhabricatorApplicationTransaction $xaction) {
switch ($xaction->getTransactionType()) {
case PhabricatorDashboardTransaction::TYPE_NAME:
if ($this->getIsNewObject()) {
return null;
}
return $object->getName();
case PhabricatorDashboardTransaction::TYPE_ICON:
if ($this->getIsNewObject()) {
return null;
}
return $object->getIcon();
case PhabricatorDashboardTransaction::TYPE_STATUS:
if ($this->getIsNewObject()) {
return null;
}
return $object->getStatus();
case PhabricatorDashboardTransaction::TYPE_LAYOUT_MODE:
if ($this->getIsNewObject()) {
return null;
}
$layout_config = $object->getLayoutConfigObject();
return $layout_config->getLayoutMode();
}
return parent::getCustomTransactionOldValue($object, $xaction);
protected function supportsSearch() {
return true;
}
protected function getCustomTransactionNewValue(
PhabricatorLiskDAO $object,
PhabricatorApplicationTransaction $xaction) {
switch ($xaction->getTransactionType()) {
case PhabricatorDashboardTransaction::TYPE_NAME:
case PhabricatorDashboardTransaction::TYPE_ICON:
case PhabricatorDashboardTransaction::TYPE_STATUS:
case PhabricatorDashboardTransaction::TYPE_LAYOUT_MODE:
return $xaction->getNewValue();
}
return parent::getCustomTransactionNewValue($object, $xaction);
}
protected function applyCustomInternalTransaction(
PhabricatorLiskDAO $object,
PhabricatorApplicationTransaction $xaction) {
switch ($xaction->getTransactionType()) {
case PhabricatorDashboardTransaction::TYPE_NAME:
$object->setName($xaction->getNewValue());
return;
case PhabricatorDashboardTransaction::TYPE_ICON:
$object->setIcon($xaction->getNewValue());
return;
case PhabricatorDashboardTransaction::TYPE_STATUS:
$object->setStatus($xaction->getNewValue());
return;
case PhabricatorDashboardTransaction::TYPE_LAYOUT_MODE:
$old_layout = $object->getLayoutConfigObject();
$new_layout = clone $old_layout;
$new_layout->setLayoutMode($xaction->getNewValue());
if ($old_layout->isMultiColumnLayout() !=
$new_layout->isMultiColumnLayout()) {
$panel_phids = $object->getPanelPHIDs();
$new_locations = $new_layout->getDefaultPanelLocations();
foreach ($panel_phids as $panel_phid) {
$new_locations[0][] = $panel_phid;
}
$new_layout->setPanelLocations($new_locations);
}
$object->setLayoutConfigFromObject($new_layout);
return;
}
return parent::applyCustomInternalTransaction($object, $xaction);
}
protected function applyCustomExternalTransaction(
PhabricatorLiskDAO $object,
PhabricatorApplicationTransaction $xaction) {
switch ($xaction->getTransactionType()) {
case PhabricatorDashboardTransaction::TYPE_NAME:
case PhabricatorDashboardTransaction::TYPE_ICON:
case PhabricatorDashboardTransaction::TYPE_STATUS:
case PhabricatorDashboardTransaction::TYPE_LAYOUT_MODE:
return;
}
return parent::applyCustomExternalTransaction($object, $xaction);
}
protected function validateTransaction(
PhabricatorLiskDAO $object,
$type,
array $xactions) {
$errors = parent::validateTransaction($object, $type, $xactions);
switch ($type) {
case PhabricatorDashboardTransaction::TYPE_NAME:
$missing = $this->validateIsEmptyTextField(
$object->getName(),
$xactions);
if ($missing) {
$error = new PhabricatorApplicationTransactionValidationError(
$type,
pht('Required'),
pht('Dashboard name is required.'),
nonempty(last($xactions), null));
$error->setIsMissingFieldError(true);
$errors[] = $error;
}
break;
}
return $errors;
}
}

View file

@ -0,0 +1,18 @@
<?php
final class PhabricatorDashboardFerretEngine
extends PhabricatorFerretEngine {
public function getApplicationName() {
return 'dashboard';
}
public function getScopeName() {
return 'dashboard';
}
public function newSearchEngine() {
return new PhabricatorDashboardSearchEngine();
}
}

View file

@ -0,0 +1,23 @@
<?php
final class PhabricatorDashboardFulltextEngine
extends PhabricatorFulltextEngine {
protected function buildAbstractDocument(
PhabricatorSearchAbstractDocument $document,
$object) {
$dashboard = $object;
$document->setDocumentTitle($dashboard->getName());
$document->addRelationship(
$dashboard->isArchived()
? PhabricatorSearchRelationship::RELATIONSHIP_CLOSED
: PhabricatorSearchRelationship::RELATIONSHIP_OPEN,
$dashboard->getPHID(),
PhabricatorDashboardDashboardPHIDType::TYPECONST,
PhabricatorTime::getNow());
}
}

View file

@ -0,0 +1,18 @@
<?php
final class PhabricatorDashboardPanelFerretEngine
extends PhabricatorFerretEngine {
public function getApplicationName() {
return 'dashboard';
}
public function getScopeName() {
return 'panel';
}
public function newSearchEngine() {
return new PhabricatorDashboardPanelSearchEngine();
}
}

View file

@ -0,0 +1,23 @@
<?php
final class PhabricatorDashboardPanelFulltextEngine
extends PhabricatorFulltextEngine {
protected function buildAbstractDocument(
PhabricatorSearchAbstractDocument $document,
$object) {
$panel = $object;
$document->setDocumentTitle($panel->getName());
$document->addRelationship(
$panel->getIsArchived()
? PhabricatorSearchRelationship::RELATIONSHIP_CLOSED
: PhabricatorSearchRelationship::RELATIONSHIP_OPEN,
$panel->getPHID(),
PhabricatorDashboardPanelPHIDType::TYPECONST,
PhabricatorTime::getNow());
}
}

View file

@ -12,16 +12,28 @@ final class PhabricatorDashboardPanelRenderingEngine extends Phobject {
private $enableAsyncRendering;
private $parentPanelPHIDs;
private $headerMode = self::HEADER_MODE_NORMAL;
private $dashboardID;
private $movable = true;
private $movable;
private $panelHandle;
private $editMode;
private $contextObject;
private $panelKey;
public function setDashboardID($id) {
$this->dashboardID = $id;
public function setContextObject($object) {
$this->contextObject = $object;
return $this;
}
public function getDashboardID() {
return $this->dashboardID;
public function getContextObject() {
return $this->contextObject;
}
public function setPanelKey($panel_key) {
$this->panelKey = $panel_key;
return $this;
}
public function getPanelKey() {
return $this->panelKey;
}
public function setHeaderMode($header_mode) {
@ -33,6 +45,24 @@ final class PhabricatorDashboardPanelRenderingEngine extends Phobject {
return $this->headerMode;
}
public function setPanelHandle(PhabricatorObjectHandle $panel_handle) {
$this->panelHandle = $panel_handle;
return $this;
}
public function getPanelHandle() {
return $this->panelHandle;
}
public function isEditMode() {
return $this->editMode;
}
public function setEditMode($mode) {
$this->editMode = $mode;
return $this;
}
/**
* Allow the engine to render the panel via Ajax.
*/
@ -90,11 +120,19 @@ final class PhabricatorDashboardPanelRenderingEngine extends Phobject {
$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();
@ -144,10 +182,10 @@ final class PhabricatorDashboardPanelRenderingEngine extends Phobject {
private function renderAsyncPanel() {
$context_phid = $this->getContextPHID();
$panel = $this->getPanel();
$panel_id = celerity_generate_unique_node_id();
$dashboard_id = $this->getDashboardID();
Javelin::initBehavior(
'dashboard-async-panel',
@ -155,7 +193,9 @@ final class PhabricatorDashboardPanelRenderingEngine extends Phobject {
'panelID' => $panel_id,
'parentPanelPHIDs' => $this->getParentPanelPHIDs(),
'headerMode' => $this->getHeaderMode(),
'dashboardID' => $dashboard_id,
'contextPHID' => $context_phid,
'panelKey' => $this->getPanelKey(),
'movable' => $this->getMovable(),
'uri' => '/dashboard/panel/render/'.$panel->getID().'/',
));
@ -185,12 +225,13 @@ final class PhabricatorDashboardPanelRenderingEngine extends Phobject {
->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);
@ -240,11 +281,11 @@ final class PhabricatorDashboardPanelRenderingEngine extends Phobject {
if ($panel) {
$box->setMetadata(
array(
'objectPHID' => $panel->getPHID(),
'panelKey' => $this->getPanelKey(),
));
}
return phutil_tag_div('dashboard-pane', $box);
return $box;
}
@ -256,8 +297,11 @@ final class PhabricatorDashboardPanelRenderingEngine extends Phobject {
$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,42 +321,65 @@ final class PhabricatorDashboardPanelRenderingEngine extends Phobject {
private function addPanelHeaderActions(
PHUIHeaderView $header) {
$panel = $this->getPanel();
$dashboard_id = $this->getDashboardID();
$viewer = $this->getViewer();
$panel = $this->getPanel();
$context_phid = $this->getContextPHID();
$actions = array();
if ($panel) {
$panel_id = $panel->getID();
$edit_uri = "/dashboard/panel/edit/{$panel_id}/";
$edit_uri = new PhutilURI($edit_uri);
if ($dashboard_id) {
$edit_uri->replaceQueryParam('dashboardID', $dashboard_id);
}
$params = array(
'contextPHID' => $context_phid,
);
$edit_uri = new PhutilURI($edit_uri, $params);
$action_edit = id(new PHUIIconView())
$actions[] = id(new PhabricatorActionView())
->setIcon('fa-pencil')
->setWorkflow(true)
->setHref((string)$edit_uri);
->setName(pht('Edit Panel'))
->setHref($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) {
if ($context_phid) {
$panel_phid = $this->getPanelPHID();
$remove_uri = "/dashboard/removepanel/{$dashboard_id}/";
$remove_uri = id(new PhutilURI($remove_uri))
->replaceQueryParam('panelPHID', $panel_phid);
$remove_uri = urisprintf('/dashboard/adjust/remove/');
$params = array(
'contextPHID' => $context_phid,
'panelKey' => $this->getPanelKey(),
);
$remove_uri = new PhutilURI($remove_uri, $params);
$action_remove = id(new PHUIIconView())
->setIcon('fa-trash-o')
->setHref((string)$remove_uri)
$actions[] = id(new PhabricatorActionView())
->setIcon('fa-times')
->setHref($remove_uri)
->setName(pht('Remove Panel'))
->setWorkflow(true);
$header->addActionItem($action_remove);
}
$dropdown_menu = id(new PhabricatorActionListView())
->setViewer($viewer);
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;
}
@ -353,5 +420,14 @@ final class PhabricatorDashboardPanelRenderingEngine extends Phobject {
}
}
private function getContextPHID() {
$context = $this->getContextObject();
if ($context) {
return $context->getPHID();
}
return null;
}
}

View file

@ -0,0 +1,18 @@
<?php
final class PhabricatorDashboardPortalFerretEngine
extends PhabricatorFerretEngine {
public function getApplicationName() {
return 'dashboard';
}
public function getScopeName() {
return 'portal';
}
public function newSearchEngine() {
return new PhabricatorDashboardPortalSearchEngine();
}
}

View file

@ -0,0 +1,23 @@
<?php
final class PhabricatorDashboardPortalFulltextEngine
extends PhabricatorFulltextEngine {
protected function buildAbstractDocument(
PhabricatorSearchAbstractDocument $document,
$object) {
$portal = $object;
$document->setDocumentTitle($portal->getName());
$document->addRelationship(
$portal->isArchived()
? PhabricatorSearchRelationship::RELATIONSHIP_CLOSED
: PhabricatorSearchRelationship::RELATIONSHIP_OPEN,
$portal->getPHID(),
PhabricatorDashboardPortalPHIDType::TYPECONST,
PhabricatorTime::getNow());
}
}

View file

@ -0,0 +1,52 @@
<?php
final class PhabricatorDashboardPortalProfileMenuEngine
extends PhabricatorProfileMenuEngine {
protected function isMenuEngineConfigurable() {
return true;
}
protected function isMenuEnginePersonalizable() {
return false;
}
public function getItemURI($path) {
$portal = $this->getProfileObject();
return $portal->getURI().$path;
}
protected function getBuiltinProfileItems($object) {
$items = array();
$items[] = $this->newDividerItem('tail');
$items[] = $this->newManageItem();
$items[] = $this->newItem()
->setMenuItemKey(PhabricatorDashboardPortalMenuItem::MENUITEMKEY)
->setBuiltinKey('manage')
->setIsTailItem(true);
return $items;
}
protected function newNoMenuItemsView(array $items) {
$object = $this->getProfileObject();
$builtins = $this->getBuiltinProfileItems($object);
if (count($items) <= count($builtins)) {
return $this->newEmptyView(
pht('New Portal'),
pht('Use "Edit Menu" to add menu items to this portal.'));
} else {
return $this->newEmptyValue(
pht('No Portal Content'),
pht(
'None of the visible menu items in this portal can render any '.
'content.'));
}
}
}

View file

@ -11,11 +11,19 @@ final class PhabricatorDashboardRenderingEngine extends Phobject {
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;
@ -23,83 +31,121 @@ final class PhabricatorDashboardRenderingEngine extends Phobject {
public function renderDashboard() {
require_celerity_resource('phabricator-dashboard-css');
$dashboard = $this->dashboard;
$viewer = $this->viewer;
$dashboard = $this->getDashboard();
$viewer = $this->getViewer();
$layout_config = $dashboard->getLayoutConfigObject();
$panel_grid_locations = $layout_config->getPanelLocations();
$panels = mpull($dashboard->getPanels(), null, 'getPHID');
$dashboard_id = celerity_generate_unique_node_id();
$result = id(new AphrontMultiColumnView())
->setID($dashboard_id)
->setFluidLayout(true)
->setGutter(AphrontMultiColumnView::GUTTER_LARGE);
$is_editable = $this->arrangeMode;
if ($this->arrangeMode) {
if ($is_editable) {
$h_mode = PhabricatorDashboardPanelRenderingEngine::HEADER_MODE_EDIT;
} else {
$h_mode = PhabricatorDashboardPanelRenderingEngine::HEADER_MODE_NORMAL;
}
foreach ($panel_grid_locations as $column => $panel_column_locations) {
$panel_phids = $panel_column_locations;
$panel_phids = $dashboard->getPanelPHIDs();
if ($panel_phids) {
$panels = id(new PhabricatorDashboardPanelQuery())
->setViewer($viewer)
->withPHIDs($panel_phids)
->execute();
$panels = mpull($panels, null, 'getPHID');
// TODO: This list may contain duplicates when the dashboard itself
// does not? Perhaps this is related to T10612. For now, just unique
// the list before moving on.
$panel_phids = array_unique($panel_phids);
$handles = $viewer->loadHandles($panel_phids);
} else {
$panels = array();
$handles = array();
}
$ref_list = $dashboard->getPanelRefList();
$columns = $ref_list->getColumns();
$dashboard_id = celerity_generate_unique_node_id();
$result = id(new AphrontMultiColumnView())
->setID($dashboard_id)
->setFluidLayout(true)
->setGutter(AphrontMultiColumnView::GUTTER_LARGE);
foreach ($columns as $column) {
$column_views = array();
foreach ($column->getPanelRefs() as $panel_ref) {
$panel_phid = $panel_ref->getPanelPHID();
$column_result = array();
foreach ($panel_phids as $panel_phid) {
$panel_engine = id(new PhabricatorDashboardPanelRenderingEngine())
->setViewer($viewer)
->setDashboardID($dashboard->getID())
->setEnableAsyncRendering(true)
->setContextObject($dashboard)
->setPanelKey($panel_ref->getPanelKey())
->setPanelPHID($panel_phid)
->setParentPanelPHIDs(array())
->setHeaderMode($h_mode);
->setHeaderMode($h_mode)
->setEditMode($is_editable)
->setMovable(true)
->setPanelHandle($handles[$panel_phid]);
$panel = idx($panels, $panel_phid);
if ($panel) {
$panel_engine->setPanel($panel);
}
$column_result[] = $panel_engine->renderPanel();
$column_views[] = $panel_engine->renderPanel();
}
$column_class = $layout_config->getColumnClass(
$column,
$this->arrangeMode);
if ($this->arrangeMode) {
$column_result[] = $this->renderAddPanelPlaceHolder($column);
$column_result[] = $this->renderAddPanelUI($column);
$column_classes = $column->getClasses();
$column_tail = array();
if ($is_editable) {
$column_tail[] = $this->renderAddPanelPlaceHolder();
$column_tail[] = $this->renderAddPanelUI($column);
}
$sigil = 'dashboard-column';
$metadata = array(
'columnKey' => $column->getColumnKey(),
);
$column_view = javelin_tag(
'div',
array(
'sigil' => $sigil,
'meta' => $metadata,
),
$column_views);
$result->addColumn(
$column_result,
$column_class,
$sigil = 'dashboard-column',
$metadata = array('columnID' => $column));
array(
$column_view,
$column_tail,
),
implode(' ', $column_classes));
}
if ($this->arrangeMode) {
if ($is_editable) {
$params = array(
'contextPHID' => $dashboard->getPHID(),
);
$move_uri = new PhutilURI('/dashboard/adjust/move/', $params);
Javelin::initBehavior(
'dashboard-move-panels',
array(
'dashboardID' => $dashboard_id,
'moveURI' => '/dashboard/movepanel/'.$dashboard->getID().'/',
'dashboardNodeID' => $dashboard_id,
'moveURI' => (string)$move_uri,
));
}
$view = id(new PHUIBoxView())
->addClass('dashboard-view')
->appendChild($result);
->appendChild(
array(
$result,
));
return $view;
}
private function renderAddPanelPlaceHolder($column) {
$dashboard = $this->dashboard;
$panels = $dashboard->getPanels();
private function renderAddPanelPlaceHolder() {
return javelin_tag(
'span',
array(
@ -109,19 +155,23 @@ final class PhabricatorDashboardRenderingEngine extends Phobject {
pht('This column does not have any panels yet.'));
}
private function renderAddPanelUI($column) {
$dashboard_id = $this->dashboard->getID();
private function renderAddPanelUI(PhabricatorDashboardColumn $column) {
$dashboard = $this->getDashboard();
$column_key = $column->getColumnKey();
$create_uri = id(new PhutilURI('/dashboard/panel/create/'))
->replaceQueryParam('dashboardID', $dashboard_id)
->replaceQueryParam('column', $column);
$create_uri = id(new PhutilURI('/dashboard/panel/edit/'))
->replaceQueryParam('contextPHID', $dashboard->getPHID())
->replaceQueryParam('columnKey', $column_key);
$add_uri = id(new PhutilURI('/dashboard/addpanel/'.$dashboard_id.'/'))
->replaceQueryParam('column', $column);
$add_uri = id(new PhutilURI('/dashboard/adjust/add/'))
->replaceQueryParam('contextPHID', $dashboard->getPHID())
->replaceQueryParam('columnKey', $column_key);
$create_button = id(new PHUIButtonView())
->setTag('a')
->setHref($create_uri)
->setIcon('fa-plus')
->setColor(PHUIButtonView::GREY)
->setWorkflow(true)
->setText(pht('Create Panel'))
->addClass(PHUI::MARGIN_MEDIUM);
@ -129,6 +179,8 @@ final class PhabricatorDashboardRenderingEngine extends Phobject {
$add_button = id(new PHUIButtonView())
->setTag('a')
->setHref($add_uri)
->setIcon('fa-window-maximize')
->setColor(PHUIButtonView::GREY)
->setWorkflow(true)
->setText(pht('Add Existing Panel'))
->addClass(PHUI::MARGIN_MEDIUM);

View file

@ -0,0 +1,28 @@
<?php
final class PhabricatorDashboardPanelContainerIndexEngineExtension
extends PhabricatorEdgeIndexEngineExtension {
const EXTENSIONKEY = 'dashboard.panel.container';
public function getExtensionName() {
return pht('Dashboard Panel Containers');
}
public function shouldIndexObject($object) {
if (!($object instanceof PhabricatorDashboardPanelContainerInterface)) {
return false;
}
return true;
}
protected function getIndexEdgeType() {
return PhabricatorObjectUsesDashboardPanelEdgeType::EDGECONST;
}
protected function getIndexDestinationPHIDs($object) {
return $object->getDashboardPanelContainerPanelPHIDs();
}
}

View file

@ -0,0 +1,58 @@
<?php
abstract class PhabricatorDashboardApplicationInstallWorkflow
extends PhabricatorDashboardInstallWorkflow {
abstract protected function newApplication();
protected function canInstallToGlobalMenu() {
return PhabricatorPolicyFilter::hasCapability(
$this->getViewer(),
$this->newApplication(),
PhabricatorPolicyCapability::CAN_EDIT);
}
public function handleRequest(AphrontRequest $request) {
$viewer = $this->getViewer();
$application = $this->newApplication();
$can_global = $this->canInstallToGlobalMenu();
switch ($this->getMode()) {
case 'global':
if (!$can_global) {
return $this->newGlobalPermissionDialog();
} else if ($request->isFormPost()) {
return $this->installDashboard($application, null);
} else {
return $this->newGlobalConfirmDialog();
}
case 'personal':
if ($request->isFormPost()) {
return $this->installDashboard($application, $viewer->getPHID());
} else {
return $this->newPersonalConfirmDialog();
}
}
$global_item = $this->newGlobalMenuItem()
->setDisabled(!$can_global);
$menu = $this->newMenuFromItemMap(
array(
'personal' => $this->newPersonalMenuItem(),
'global' => $global_item,
));
return $this->newApplicationModeDialog()
->appendChild($menu);
}
abstract protected function newGlobalPermissionDialog();
abstract protected function newGlobalConfirmDialog();
abstract protected function newPersonalConfirmDialog();
abstract protected function newPersonalMenuItem();
abstract protected function newGlobalMenuItem();
abstract protected function newApplicationModeDialog();
}

View file

@ -0,0 +1,85 @@
<?php
final class PhabricatorDashboardFavoritesInstallWorkflow
extends PhabricatorDashboardApplicationInstallWorkflow {
const WORKFLOWKEY = 'favorites';
public function getOrder() {
return 4000;
}
protected function newWorkflowMenuItem() {
return $this->newMenuItem()
->setHeader(pht('Add to Favorites Menu'))
->setImageIcon('fa-bookmark')
->addAttribute(
pht(
'Add this dashboard to the favorites menu in the main '.
'menu bar.'));
}
protected function newProfileEngine() {
return new PhabricatorFavoritesProfileMenuEngine();
}
protected function newApplication() {
return new PhabricatorFavoritesApplication();
}
protected function newApplicationModeDialog() {
return $this->newDialog()
->setTitle(pht('Add Dashboard to Favorites Menu'));
}
protected function newPersonalMenuItem() {
return $this->newMenuItem()
->setHeader(pht('Add to Personal Favorites'))
->setImageIcon('fa-user')
->addAttribute(
pht(
'Add this dashboard to your list of personal favorite menu items, '.
'visible to only you.'));
}
protected function newGlobalMenuItem() {
return $this->newMenuItem()
->setHeader(pht('Add to Global Favorites'))
->setImageIcon('fa-globe')
->addAttribute(
pht(
'Add this dashboard to the global favorites menu, visible to all '.
'users.'));
}
protected function newGlobalPermissionDialog() {
return $this->newDialog()
->setTitle(pht('No Permission'))
->appendParagraph(
pht(
'You do not have permission to install items on the global '.
'favorites menu.'));
}
protected function newGlobalConfirmDialog() {
return $this->newDialog()
->setTitle(pht('Add Dashboard to Global Favorites'))
->appendParagraph(
pht(
'Add dashboard %s as a global menu item in the favorites menu?',
$this->getDashboardDisplayName()))
->addSubmitButton(pht('Add to Favorites'));
}
protected function newPersonalConfirmDialog() {
return $this->newDialog()
->setTitle(pht('Add Dashboard to Personal Favorites'))
->appendParagraph(
pht(
'Add dashboard %s as a personal menu item in the favorites menu?',
$this->getDashboardDisplayName()))
->addSubmitButton(pht('Add to Favorites'));
}
}

View file

@ -0,0 +1,83 @@
<?php
final class PhabricatorDashboardHomeInstallWorkflow
extends PhabricatorDashboardApplicationInstallWorkflow {
const WORKFLOWKEY = 'home';
public function getOrder() {
return 1000;
}
protected function newWorkflowMenuItem() {
return $this->newMenuItem()
->setHeader(pht('Add to Home Page Menu'))
->setImageIcon('fa-home')
->addAttribute(
pht(
'Add this dashboard to the menu on the home page.'));
}
protected function newProfileEngine() {
return new PhabricatorHomeProfileMenuEngine();
}
protected function newApplication() {
return new PhabricatorHomeApplication();
}
protected function newApplicationModeDialog() {
return $this->newDialog()
->setTitle(pht('Add Dashboard to Home Menu'));
}
protected function newPersonalMenuItem() {
return $this->newMenuItem()
->setHeader(pht('Add to Personal Home Menu'))
->setImageIcon('fa-user')
->addAttribute(
pht(
'Add this dashboard to your list of personal home menu items, '.
'visible to only you.'));
}
protected function newGlobalMenuItem() {
return $this->newMenuItem()
->setHeader(pht('Add to Global Home Menu'))
->setImageIcon('fa-globe')
->addAttribute(
pht(
'Add this dashboard to the global home menu, visible to all '.
'users.'));
}
protected function newGlobalPermissionDialog() {
return $this->newDialog()
->setTitle(pht('No Permission'))
->appendParagraph(
pht(
'You do not have permission to install items on the global home '.
'menu.'));
}
protected function newGlobalConfirmDialog() {
return $this->newDialog()
->setTitle(pht('Add Dashboard to Global Home Page'))
->appendParagraph(
pht(
'Add dashboard %s as a global menu item on the home page?',
$this->getDashboardDisplayName()))
->addSubmitButton(pht('Add to Home'));
}
protected function newPersonalConfirmDialog() {
return $this->newDialog()
->setTitle(pht('Add Dashboard to Personal Home Page'))
->appendParagraph(
pht(
'Add dashboard %s as a personal menu item on your home page?',
$this->getDashboardDisplayName()))
->addSubmitButton(pht('Add to Home'));
}
}

View file

@ -0,0 +1,143 @@
<?php
abstract class PhabricatorDashboardInstallWorkflow
extends Phobject {
private $request;
private $viewer;
private $dashboard;
private $mode;
final public function setViewer(PhabricatorUser $viewer) {
$this->viewer = $viewer;
return $this;
}
final public function getViewer() {
return $this->viewer;
}
final public function setDashboard(PhabricatorDashboard $dashboard) {
$this->dashboard = $dashboard;
return $this;
}
final public function getDashboard() {
return $this->dashboard;
}
final public function setMode($mode) {
$this->mode = $mode;
return $this;
}
final public function getMode() {
return $this->mode;
}
final public function setRequest(AphrontRequest $request) {
$this->request = $request;
return $this;
}
final public function getRequest() {
return $this->request;
}
final public function getWorkflowKey() {
return $this->getPhobjectClassConstant('WORKFLOWKEY', 32);
}
final public static function getAllWorkflows() {
return id(new PhutilClassMapQuery())
->setAncestorClass(__CLASS__)
->setUniqueMethod('getWorkflowKey')
->setSortMethod('getOrder')
->execute();
}
final public function getWorkflowMenuItem() {
return $this->newWorkflowMenuItem();
}
abstract public function getOrder();
abstract protected function newWorkflowMenuItem();
final protected function newMenuItem() {
return id(new PHUIObjectItemView())
->setClickable(true);
}
abstract public function handleRequest(AphrontRequest $request);
final protected function newDialog() {
$dashboard = $this->getDashboard();
return id(new AphrontDialogView())
->setViewer($this->getViewer())
->setWidth(AphrontDialogView::WIDTH_FORM)
->addCancelButton($dashboard->getURI());
}
final protected function newMenuFromItemMap(array $map) {
$viewer = $this->getViewer();
$dashboard = $this->getDashboard();
$menu = id(new PHUIObjectItemListView())
->setViewer($viewer)
->setFlush(true)
->setBig(true);
foreach ($map as $key => $item) {
$item->setHref(
urisprintf(
'/dashboard/install/%d/%s/%s/',
$dashboard->getID(),
$this->getWorkflowKey(),
$key));
$menu->addItem($item);
}
return $menu;
}
abstract protected function newProfileEngine();
final protected function installDashboard($profile_object, $custom_phid) {
$dashboard = $this->getDashboard();
$engine = $this->newProfileEngine()
->setProfileObject($profile_object);
$request = $this->getRequest();
$viewer = $this->getViewer();
$config = PhabricatorProfileMenuItemConfiguration::initializeNewItem(
$profile_object,
new PhabricatorDashboardProfileMenuItem(),
$custom_phid);
$config->setMenuItemProperty('dashboardPHID', $dashboard->getPHID());
$xactions = array();
$editor = id(new PhabricatorProfileMenuEditor())
->setActor($viewer)
->setContinueOnNoEffect(true)
->setContinueOnMissingFields(true)
->setContentSourceFromRequest($request);
$editor->applyTransactions($config, $xactions);
$done_uri = $engine->getItemURI(urisprintf('view/%d/', $config->getID()));
return id(new AphrontRedirectResponse())
->setURI($done_uri);
}
final protected function getDashboardDisplayName() {
$dashboard = $this->getDashboard();
return phutil_tag('strong', array(), $dashboard->getName());
}
}

View file

@ -0,0 +1,99 @@
<?php
abstract class PhabricatorDashboardObjectInstallWorkflow
extends PhabricatorDashboardInstallWorkflow {
abstract protected function newQuery();
abstract protected function newConfirmDialog($object);
abstract protected function newObjectSelectionForm($object);
public function handleRequest(AphrontRequest $request) {
$viewer = $this->getViewer();
$target_identifier = null;
$target_tokens = $request->getArr('target');
if ($target_tokens) {
$target_identifier = head($target_tokens);
}
if (!strlen($target_identifier)) {
$target_identifier = $request->getStr('target');
}
if (!strlen($target_identifier)) {
$target_identifier = $this->getMode();
}
$target = null;
if (strlen($target_identifier)) {
$targets = array();
if (ctype_digit($target_identifier)) {
$targets = $this->newQuery()
->setViewer($viewer)
->withIDs(array((int)$target_identifier))
->execute();
}
if (!$targets) {
$targets = $this->newQuery()
->setViewer($viewer)
->withPHIDs(array($target_identifier))
->execute();
}
if ($targets) {
$target = head($targets);
}
}
if ($target) {
$target_phid = $target->getPHID();
} else {
$target_phid = null;
}
if ($target) {
$can_edit = PhabricatorPolicyFilter::hasCapability(
$viewer,
$target,
PhabricatorPolicyCapability::CAN_EDIT);
} else {
$can_edit = null;
}
if ($request->isFormPost() && $target && $can_edit) {
if ($request->getBool('confirm')) {
return $this->installDashboard($target, null);
} else {
return $this->newConfirmDialog($target)
->addHiddenInput('confirm', 1)
->addHiddenInput('target', $target_phid);
}
}
$errors = array();
if (strlen($target_identifier)) {
if (!$target) {
$errors[] = pht('Choose a valid object.');
} else if (!$can_edit) {
$errors[] = pht(
'You do not have permission to edit the selected object. '.
'You can only install dashboards on objects you can edit.');
}
} else if ($request->getBool('pick')) {
$errors[] = pht(
'Choose an object to install this dashboard on.');
}
$form = $this->newObjectSelectionForm($target)
->addHiddenInput('pick', 1);
return $this->newDialog()
->setTitle(pht('Add Dashboard to Project Menu'))
->setErrors($errors)
->appendForm($form)
->addSubmitButton(pht('Continue'));
}
}

View file

@ -0,0 +1,62 @@
<?php
final class PhabricatorDashboardPortalInstallWorkflow
extends PhabricatorDashboardObjectInstallWorkflow {
const WORKFLOWKEY = 'portal';
public function getOrder() {
return 2000;
}
protected function newWorkflowMenuItem() {
return $this->newMenuItem()
->setHeader(pht('Add to Portal Menu'))
->setImageIcon('fa-compass')
->addAttribute(
pht('Add this dashboard to the menu on a portal.'));
}
protected function newProfileEngine() {
return new PhabricatorDashboardPortalProfileMenuEngine();
}
protected function newQuery() {
return new PhabricatorDashboardPortalQuery();
}
protected function newConfirmDialog($object) {
return $this->newDialog()
->setTitle(pht('Add Dashboard to Portal Menu'))
->appendParagraph(
pht(
'Add the dashboard %s to portal %s?',
$this->getDashboardDisplayName(),
phutil_tag('strong', array(), $object->getName())))
->addSubmitButton(pht('Add to Portal'));
}
protected function newObjectSelectionForm($object) {
$viewer = $this->getViewer();
if ($object) {
$tokenizer_value = array($object->getPHID());
} else {
$tokenizer_value = array();
}
return id(new AphrontFormView())
->setViewer($viewer)
->appendInstructions(
pht(
'Select which portal you want to add the dashboard %s to.',
$this->getDashboardDisplayName()))
->appendControl(
id(new AphrontFormTokenizerControl())
->setName('target')
->setLimit(1)
->setLabel(pht('Add to Portal'))
->setValue($tokenizer_value)
->setDatasource(new PhabricatorDashboardPortalDatasource()));
}
}

View file

@ -0,0 +1,63 @@
<?php
final class PhabricatorDashboardProjectInstallWorkflow
extends PhabricatorDashboardObjectInstallWorkflow {
const WORKFLOWKEY = 'project';
public function getOrder() {
return 3000;
}
protected function newWorkflowMenuItem() {
return $this->newMenuItem()
->setHeader(pht('Add to Project Menu'))
->setImageIcon('fa-briefcase')
->addAttribute(
pht('Add this dashboard to the menu for a project.'));
}
protected function newProfileEngine() {
return new PhabricatorProjectProfileMenuEngine();
}
protected function newQuery() {
return new PhabricatorProjectQuery();
}
protected function newConfirmDialog($object) {
return $this->newDialog()
->setTitle(pht('Add Dashboard to Project Menu'))
->appendParagraph(
pht(
'Add the dashboard %s to the menu for project %s?',
$this->getDashboardDisplayName(),
phutil_tag('strong', array(), $object->getName())))
->addSubmitButton(pht('Add to Project'));
}
protected function newObjectSelectionForm($object) {
$viewer = $this->getViewer();
if ($object) {
$tokenizer_value = array($object->getPHID());
} else {
$tokenizer_value = array();
}
return id(new AphrontFormView())
->setViewer($viewer)
->appendInstructions(
pht(
'Select which project menu you want to add the dashboard %s to.',
$this->getDashboardDisplayName()))
->appendControl(
id(new AphrontFormTokenizerControl())
->setName('target')
->setLimit(1)
->setLabel(pht('Add to Project'))
->setValue($tokenizer_value)
->setDatasource(new PhabricatorProjectDatasource()));
}
}

View file

@ -0,0 +1,12 @@
<?php
interface PhabricatorDashboardPanelContainerInterface {
/**
* Return a list of Dashboard Panel PHIDs used by this container.
*
* @return list<phid>
*/
public function getDashboardPanelContainerPanelPHIDs();
}

View file

@ -0,0 +1,43 @@
<?php
final class PhabricatorDashboardColumn
extends Phobject {
private $columnKey;
private $classes = array();
private $refs = array();
public function setColumnKey($column_key) {
$this->columnKey = $column_key;
return $this;
}
public function getColumnKey() {
return $this->columnKey;
}
public function addClass($class) {
$this->classes[] = $class;
return $this;
}
public function getClasses() {
return $this->classes;
}
public function setPanelRefs(array $refs) {
assert_instances_of($refs, 'PhabricatorDashboardPanelRef');
$this->refs = $refs;
return $this;
}
public function addPanelRef(PhabricatorDashboardPanelRef $ref) {
$this->refs[] = $ref;
return $this;
}
public function getPanelRefs() {
return $this->refs;
}
}

View file

@ -0,0 +1,23 @@
<?php
final class PhabricatorDashboardFullLayoutMode
extends PhabricatorDashboardLayoutMode {
const LAYOUTMODE = 'layout-mode-full';
public function getLayoutModeOrder() {
return 0;
}
public function getLayoutModeName() {
return pht('One Column: 100%%');
}
public function getLayoutModeColumns() {
return array(
$this->newColumn()
->setColumnKey('main'),
);
}
}

Some files were not shown because too many files have changed in this diff Show more