mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-16 02:20:54 +01:00
(stable) Promote 2017 Week 34
This commit is contained in:
commit
77c11e7ae9
46 changed files with 1276 additions and 367 deletions
|
@ -9,8 +9,8 @@ return array(
|
|||
'names' => array(
|
||||
'conpherence.pkg.css' => 'e68cf1fa',
|
||||
'conpherence.pkg.js' => 'b5b51108',
|
||||
'core.pkg.css' => 'fe4effd6',
|
||||
'core.pkg.js' => '5d80e0db',
|
||||
'core.pkg.css' => '291cbd98',
|
||||
'core.pkg.js' => '6c085267',
|
||||
'darkconsole.pkg.js' => '1f9a31bc',
|
||||
'differential.pkg.css' => '45951e9e',
|
||||
'differential.pkg.js' => 'b71b8c5d',
|
||||
|
@ -39,7 +39,7 @@ return array(
|
|||
'rsrc/css/aphront/typeahead.css' => 'a4a21016',
|
||||
'rsrc/css/application/almanac/almanac.css' => 'dbb9b3af',
|
||||
'rsrc/css/application/auth/auth.css' => '0877ed6e',
|
||||
'rsrc/css/application/base/main-menu-view.css' => '16053029',
|
||||
'rsrc/css/application/base/main-menu-view.css' => '1802a242',
|
||||
'rsrc/css/application/base/notification-menu.css' => '73fefdfa',
|
||||
'rsrc/css/application/base/phui-theme.css' => '9f261c6b',
|
||||
'rsrc/css/application/base/standard-page-view.css' => '34ee718b',
|
||||
|
@ -74,7 +74,7 @@ return array(
|
|||
'rsrc/css/application/diffusion/diffusion-icons.css' => '0c15255e',
|
||||
'rsrc/css/application/diffusion/diffusion-readme.css' => '419dd5b6',
|
||||
'rsrc/css/application/diffusion/diffusion-repository.css' => 'ee6f20ec',
|
||||
'rsrc/css/application/diffusion/diffusion-source.css' => '750add59',
|
||||
'rsrc/css/application/diffusion/diffusion-source.css' => '47db8a7c',
|
||||
'rsrc/css/application/diffusion/diffusion.css' => 'ceacf994',
|
||||
'rsrc/css/application/feed/feed.css' => 'ecd4ec57',
|
||||
'rsrc/css/application/files/global-drag-and-drop.css' => 'b556a948',
|
||||
|
@ -127,7 +127,7 @@ return array(
|
|||
'rsrc/css/layout/phabricator-source-code-view.css' => 'aea41829',
|
||||
'rsrc/css/phui/button/phui-button-bar.css' => 'f1ff5494',
|
||||
'rsrc/css/phui/button/phui-button-simple.css' => '8e1baf68',
|
||||
'rsrc/css/phui/button/phui-button.css' => '340f55c1',
|
||||
'rsrc/css/phui/button/phui-button.css' => 'a37aa3a8',
|
||||
'rsrc/css/phui/calendar/phui-calendar-day.css' => '572b1893',
|
||||
'rsrc/css/phui/calendar/phui-calendar-list.css' => '576be600',
|
||||
'rsrc/css/phui/calendar/phui-calendar-month.css' => '21154caf',
|
||||
|
@ -138,7 +138,7 @@ return array(
|
|||
'rsrc/css/phui/object-item/phui-oi-flush-ui.css' => '9d9685d6',
|
||||
'rsrc/css/phui/object-item/phui-oi-list-view.css' => 'bf094950',
|
||||
'rsrc/css/phui/object-item/phui-oi-simple-ui.css' => 'a8beebea',
|
||||
'rsrc/css/phui/phui-action-list.css' => '6ee16164',
|
||||
'rsrc/css/phui/phui-action-list.css' => 'e7eba156',
|
||||
'rsrc/css/phui/phui-action-panel.css' => 'b4798122',
|
||||
'rsrc/css/phui/phui-badge.css' => '22c0cf4f',
|
||||
'rsrc/css/phui/phui-basic-nav-view.css' => 'a0705f53',
|
||||
|
@ -158,7 +158,7 @@ return array(
|
|||
'rsrc/css/phui/phui-form-view.css' => 'ae9f8d16',
|
||||
'rsrc/css/phui/phui-form.css' => '7aaa04e3',
|
||||
'rsrc/css/phui/phui-head-thing.css' => 'fd311e5f',
|
||||
'rsrc/css/phui/phui-header-view.css' => 'e7de7ee2',
|
||||
'rsrc/css/phui/phui-header-view.css' => '808b82c7',
|
||||
'rsrc/css/phui/phui-hovercard.css' => 'f0592bcf',
|
||||
'rsrc/css/phui/phui-icon-set-selector.css' => '87db8fee',
|
||||
'rsrc/css/phui/phui-icon.css' => '5c4a5de6',
|
||||
|
@ -375,9 +375,9 @@ return array(
|
|||
'rsrc/image/texture/table_header_tall.png' => 'd56b434f',
|
||||
'rsrc/js/application/aphlict/Aphlict.js' => 'e1d4b11a',
|
||||
'rsrc/js/application/aphlict/behavior-aphlict-dropdown.js' => 'caade6f2',
|
||||
'rsrc/js/application/aphlict/behavior-aphlict-listen.js' => '3c547a81',
|
||||
'rsrc/js/application/aphlict/behavior-aphlict-listen.js' => 'a14cbdfc',
|
||||
'rsrc/js/application/aphlict/behavior-aphlict-status.js' => '5e2634b9',
|
||||
'rsrc/js/application/aphlict/behavior-desktop-notifications-control.js' => 'd5a2d665',
|
||||
'rsrc/js/application/aphlict/behavior-desktop-notifications-control.js' => '27ca6289',
|
||||
'rsrc/js/application/calendar/behavior-day-view.js' => '4b3c4443',
|
||||
'rsrc/js/application/calendar/behavior-event-all-day.js' => 'b41537c9',
|
||||
'rsrc/js/application/calendar/behavior-month-view.js' => 'fe33e256',
|
||||
|
@ -452,7 +452,7 @@ return array(
|
|||
'rsrc/js/application/transactions/behavior-comment-actions.js' => '9a6dd75c',
|
||||
'rsrc/js/application/transactions/behavior-reorder-configs.js' => 'd7a74243',
|
||||
'rsrc/js/application/transactions/behavior-reorder-fields.js' => 'b59e1e96',
|
||||
'rsrc/js/application/transactions/behavior-show-older-transactions.js' => 'ae95d984',
|
||||
'rsrc/js/application/transactions/behavior-show-older-transactions.js' => '8f29b364',
|
||||
'rsrc/js/application/transactions/behavior-transaction-comment-form.js' => 'b23b49e6',
|
||||
'rsrc/js/application/transactions/behavior-transaction-list.js' => '1f6794f6',
|
||||
'rsrc/js/application/typeahead/behavior-typeahead-browse.js' => '635de1ec',
|
||||
|
@ -468,7 +468,7 @@ return array(
|
|||
'rsrc/js/core/KeyboardShortcut.js' => '1ae869f2',
|
||||
'rsrc/js/core/KeyboardShortcutManager.js' => 'c19dd9b9',
|
||||
'rsrc/js/core/MultirowRowManager.js' => 'b5d57730',
|
||||
'rsrc/js/core/Notification.js' => 'ccf1cbf8',
|
||||
'rsrc/js/core/Notification.js' => '5c3349b2',
|
||||
'rsrc/js/core/Prefab.js' => 'c5af80a2',
|
||||
'rsrc/js/core/ShapedRequest.js' => '7cbe244b',
|
||||
'rsrc/js/core/TextAreaUtils.js' => '320810c8',
|
||||
|
@ -574,7 +574,7 @@ return array(
|
|||
'diffusion-icons-css' => '0c15255e',
|
||||
'diffusion-readme-css' => '419dd5b6',
|
||||
'diffusion-repository-css' => 'ee6f20ec',
|
||||
'diffusion-source-css' => '750add59',
|
||||
'diffusion-source-css' => '47db8a7c',
|
||||
'diviner-shared-css' => '896f1d43',
|
||||
'font-fontawesome' => 'e838e088',
|
||||
'font-lato' => 'c7ccd872',
|
||||
|
@ -587,7 +587,7 @@ return array(
|
|||
'javelin-aphlict' => 'e1d4b11a',
|
||||
'javelin-behavior' => '61cbc29a',
|
||||
'javelin-behavior-aphlict-dropdown' => 'caade6f2',
|
||||
'javelin-behavior-aphlict-listen' => '3c547a81',
|
||||
'javelin-behavior-aphlict-listen' => 'a14cbdfc',
|
||||
'javelin-behavior-aphlict-status' => '5e2634b9',
|
||||
'javelin-behavior-aphront-basic-tokenizer' => 'b3a4b884',
|
||||
'javelin-behavior-aphront-drag-and-drop-textarea' => '484a6e22',
|
||||
|
@ -612,7 +612,7 @@ return array(
|
|||
'javelin-behavior-dashboard-query-panel-select' => '453c5375',
|
||||
'javelin-behavior-dashboard-tab-panel' => 'd4eecc63',
|
||||
'javelin-behavior-day-view' => '4b3c4443',
|
||||
'javelin-behavior-desktop-notifications-control' => 'd5a2d665',
|
||||
'javelin-behavior-desktop-notifications-control' => '27ca6289',
|
||||
'javelin-behavior-detect-timezone' => '4c193c96',
|
||||
'javelin-behavior-device' => 'bb1dd507',
|
||||
'javelin-behavior-diff-preview-link' => '051c7832',
|
||||
|
@ -665,7 +665,7 @@ return array(
|
|||
'javelin-behavior-phabricator-remarkup-assist' => 'acd29eee',
|
||||
'javelin-behavior-phabricator-reveal-content' => '60821bc7',
|
||||
'javelin-behavior-phabricator-search-typeahead' => 'd0a99ab4',
|
||||
'javelin-behavior-phabricator-show-older-transactions' => 'ae95d984',
|
||||
'javelin-behavior-phabricator-show-older-transactions' => '8f29b364',
|
||||
'javelin-behavior-phabricator-tooltips' => 'c420b0b9',
|
||||
'javelin-behavior-phabricator-transaction-comment-form' => 'b23b49e6',
|
||||
'javelin-behavior-phabricator-transaction-list' => '1f6794f6',
|
||||
|
@ -767,7 +767,7 @@ return array(
|
|||
'path-typeahead' => 'f7fc67ec',
|
||||
'people-picture-menu-item-css' => 'a06f7f34',
|
||||
'people-profile-css' => '4df76faf',
|
||||
'phabricator-action-list-view-css' => '6ee16164',
|
||||
'phabricator-action-list-view-css' => 'e7eba156',
|
||||
'phabricator-busy' => '59a7976a',
|
||||
'phabricator-chatlog-css' => 'd295b020',
|
||||
'phabricator-content-source-view-css' => '4b8b05d4',
|
||||
|
@ -789,9 +789,9 @@ return array(
|
|||
'phabricator-flag-css' => 'bba8f811',
|
||||
'phabricator-keyboard-shortcut' => '1ae869f2',
|
||||
'phabricator-keyboard-shortcut-manager' => 'c19dd9b9',
|
||||
'phabricator-main-menu-view' => '16053029',
|
||||
'phabricator-main-menu-view' => '1802a242',
|
||||
'phabricator-nav-view-css' => 'faf6a6fc',
|
||||
'phabricator-notification' => 'ccf1cbf8',
|
||||
'phabricator-notification' => '5c3349b2',
|
||||
'phabricator-notification-css' => '3f6c89c9',
|
||||
'phabricator-notification-menu-css' => '73fefdfa',
|
||||
'phabricator-object-selector-css' => '85ee8ce6',
|
||||
|
@ -824,7 +824,7 @@ return array(
|
|||
'phui-big-info-view-css' => 'acc3492c',
|
||||
'phui-box-css' => '745e881d',
|
||||
'phui-button-bar-css' => 'f1ff5494',
|
||||
'phui-button-css' => '340f55c1',
|
||||
'phui-button-css' => 'a37aa3a8',
|
||||
'phui-button-simple-css' => '8e1baf68',
|
||||
'phui-calendar-css' => 'f1ddf11c',
|
||||
'phui-calendar-day-css' => '572b1893',
|
||||
|
@ -845,7 +845,7 @@ return array(
|
|||
'phui-form-css' => '7aaa04e3',
|
||||
'phui-form-view-css' => 'ae9f8d16',
|
||||
'phui-head-thing-view-css' => 'fd311e5f',
|
||||
'phui-header-view-css' => 'e7de7ee2',
|
||||
'phui-header-view-css' => '808b82c7',
|
||||
'phui-hovercard' => '1bd28176',
|
||||
'phui-hovercard-view-css' => 'f0592bcf',
|
||||
'phui-icon-set-selector-css' => '87db8fee',
|
||||
|
@ -981,9 +981,6 @@ return array(
|
|||
'aphront-typeahead-control-css',
|
||||
'phui-tag-view-css',
|
||||
),
|
||||
16053029 => array(
|
||||
'phui-theme-css',
|
||||
),
|
||||
'17bb8539' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-stratcom',
|
||||
|
@ -994,6 +991,9 @@ return array(
|
|||
'phabricator-darklog',
|
||||
'phabricator-darkmessage',
|
||||
),
|
||||
'1802a242' => array(
|
||||
'phui-theme-css',
|
||||
),
|
||||
'185bbd53' => array(
|
||||
'javelin-install',
|
||||
),
|
||||
|
@ -1058,6 +1058,13 @@ return array(
|
|||
'phabricator-drag-and-drop-file-upload',
|
||||
'javelin-workboard-board',
|
||||
),
|
||||
'27ca6289' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-stratcom',
|
||||
'javelin-dom',
|
||||
'javelin-uri',
|
||||
'phabricator-notification',
|
||||
),
|
||||
'2926fff2' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-dom',
|
||||
|
@ -1115,20 +1122,6 @@ return array(
|
|||
'javelin-dom',
|
||||
'javelin-magical-init',
|
||||
),
|
||||
'3c547a81' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-aphlict',
|
||||
'javelin-stratcom',
|
||||
'javelin-request',
|
||||
'javelin-uri',
|
||||
'javelin-dom',
|
||||
'javelin-json',
|
||||
'javelin-router',
|
||||
'javelin-util',
|
||||
'javelin-leader',
|
||||
'javelin-sound',
|
||||
'phabricator-notification',
|
||||
),
|
||||
'3cb0b2fc' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-dom',
|
||||
|
@ -1338,6 +1331,13 @@ return array(
|
|||
'javelin-vector',
|
||||
'javelin-dom',
|
||||
),
|
||||
'5c3349b2' => array(
|
||||
'javelin-install',
|
||||
'javelin-dom',
|
||||
'javelin-stratcom',
|
||||
'javelin-util',
|
||||
'phabricator-notification-css',
|
||||
),
|
||||
'5c54cbf3' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-stratcom',
|
||||
|
@ -1575,6 +1575,12 @@ return array(
|
|||
'javelin-install',
|
||||
'phuix-button-view',
|
||||
),
|
||||
'8f29b364' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-stratcom',
|
||||
'javelin-dom',
|
||||
'phabricator-busy',
|
||||
),
|
||||
'8ff5e24c' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-stratcom',
|
||||
|
@ -1676,6 +1682,20 @@ return array(
|
|||
'javelin-util',
|
||||
'phabricator-keyboard-shortcut',
|
||||
),
|
||||
'a14cbdfc' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-aphlict',
|
||||
'javelin-stratcom',
|
||||
'javelin-request',
|
||||
'javelin-uri',
|
||||
'javelin-dom',
|
||||
'javelin-json',
|
||||
'javelin-router',
|
||||
'javelin-util',
|
||||
'javelin-leader',
|
||||
'javelin-sound',
|
||||
'phabricator-notification',
|
||||
),
|
||||
'a37126bd' => array(
|
||||
'javelin-install',
|
||||
'javelin-dom',
|
||||
|
@ -1751,12 +1771,6 @@ return array(
|
|||
'phuix-autocomplete',
|
||||
'javelin-mask',
|
||||
),
|
||||
'ae95d984' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-stratcom',
|
||||
'javelin-dom',
|
||||
'phabricator-busy',
|
||||
),
|
||||
'b003d4fb' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-stratcom',
|
||||
|
@ -1951,13 +1965,6 @@ return array(
|
|||
'cae95e89' => array(
|
||||
'syntax-default-css',
|
||||
),
|
||||
'ccf1cbf8' => array(
|
||||
'javelin-install',
|
||||
'javelin-dom',
|
||||
'javelin-stratcom',
|
||||
'javelin-util',
|
||||
'phabricator-notification-css',
|
||||
),
|
||||
'cd2b9b77' => array(
|
||||
'phui-oi-list-view-css',
|
||||
),
|
||||
|
@ -1996,13 +2003,6 @@ return array(
|
|||
'javelin-dom',
|
||||
'javelin-stratcom',
|
||||
),
|
||||
'd5a2d665' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-stratcom',
|
||||
'javelin-dom',
|
||||
'javelin-uri',
|
||||
'phabricator-notification',
|
||||
),
|
||||
'd6a7e717' => array(
|
||||
'multirow-row-manager',
|
||||
'javelin-install',
|
||||
|
|
9
resources/sql/autopatches/20170814.search.01.qconfig.sql
Normal file
9
resources/sql/autopatches/20170814.search.01.qconfig.sql
Normal file
|
@ -0,0 +1,9 @@
|
|||
CREATE TABLE {$NAMESPACE}_search.search_namedqueryconfig (
|
||||
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
engineClassName VARCHAR(128) NOT NULL COLLATE {$COLLATE_TEXT},
|
||||
scopePHID VARBINARY(64) NOT NULL,
|
||||
properties LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT},
|
||||
dateCreated INT UNSIGNED NOT NULL,
|
||||
dateModified INT UNSIGNED NOT NULL,
|
||||
UNIQUE KEY `key_scope` (engineClassName, scopePHID)
|
||||
) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};
|
46
resources/sql/autopatches/20170824.search.01.saved.php
Normal file
46
resources/sql/autopatches/20170824.search.01.saved.php
Normal file
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
// Before T12956, normal users could reorder (and disable) builtin queries.
|
||||
// After that change, there is a single global order which can only be
|
||||
// changed by administrators.
|
||||
|
||||
// This migration removes the rows which store individual reordering and
|
||||
// disabling of queries. If a user had reordered queries in such a way that
|
||||
// a builtin query was at the top of the list, we try to write a preference
|
||||
// which pins that query as their default to minimize disruption.
|
||||
|
||||
$table = new PhabricatorNamedQuery();
|
||||
$conn = $table->establishConnection('w');
|
||||
|
||||
$config_table = new PhabricatorNamedQueryConfig();
|
||||
|
||||
foreach (new LiskMigrationIterator($table) as $named_query) {
|
||||
|
||||
// If this isn't a builtin query, it isn't changing. Leave it alone.
|
||||
if (!$named_query->getIsBuiltin()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the user reordered things but left a builtin query at the top, pin
|
||||
// the query before we remove the row.
|
||||
if ($named_query->getSequence() == 1) {
|
||||
queryfx(
|
||||
$conn,
|
||||
'INSERT IGNORE INTO %T
|
||||
(engineClassName, scopePHID, properties, dateCreated, dateModified)
|
||||
VALUES
|
||||
(%s, %s, %s, %d, %d)',
|
||||
$config_table->getTableName(),
|
||||
$named_query->getEngineClassName(),
|
||||
$named_query->getUserPHID(),
|
||||
phutil_json_encode(
|
||||
array(
|
||||
PhabricatorNamedQueryConfig::PROPERTY_PINNED =>
|
||||
$named_query->getQueryKey(),
|
||||
)),
|
||||
PhabricatorTime::getNow(),
|
||||
PhabricatorTime::getNow());
|
||||
}
|
||||
|
||||
$named_query->delete();
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE {$NAMESPACE}_phame.phame_post
|
||||
DROP COLUMN views;
|
|
@ -544,6 +544,7 @@ phutil_register_library_map(array(
|
|||
'DifferentialRevisionHeraldField' => 'applications/differential/herald/DifferentialRevisionHeraldField.php',
|
||||
'DifferentialRevisionHeraldFieldGroup' => 'applications/differential/herald/DifferentialRevisionHeraldFieldGroup.php',
|
||||
'DifferentialRevisionIDCommitMessageField' => 'applications/differential/field/DifferentialRevisionIDCommitMessageField.php',
|
||||
'DifferentialRevisionInlineTransaction' => 'applications/differential/xaction/DifferentialRevisionInlineTransaction.php',
|
||||
'DifferentialRevisionInlinesController' => 'applications/differential/controller/DifferentialRevisionInlinesController.php',
|
||||
'DifferentialRevisionListController' => 'applications/differential/controller/DifferentialRevisionListController.php',
|
||||
'DifferentialRevisionListView' => 'applications/differential/view/DifferentialRevisionListView.php',
|
||||
|
@ -2647,8 +2648,6 @@ phutil_register_library_map(array(
|
|||
'PhabricatorDebugController' => 'applications/system/controller/PhabricatorDebugController.php',
|
||||
'PhabricatorDefaultRequestExceptionHandler' => 'aphront/handler/PhabricatorDefaultRequestExceptionHandler.php',
|
||||
'PhabricatorDefaultSyntaxStyle' => 'infrastructure/syntax/PhabricatorDefaultSyntaxStyle.php',
|
||||
'PhabricatorDesktopNotificationsSetting' => 'applications/settings/setting/PhabricatorDesktopNotificationsSetting.php',
|
||||
'PhabricatorDesktopNotificationsSettingsPanel' => 'applications/settings/panel/PhabricatorDesktopNotificationsSettingsPanel.php',
|
||||
'PhabricatorDestructibleCodex' => 'applications/system/codex/PhabricatorDestructibleCodex.php',
|
||||
'PhabricatorDestructibleCodexInterface' => 'applications/system/interface/PhabricatorDestructibleCodexInterface.php',
|
||||
'PhabricatorDestructibleInterface' => 'applications/system/interface/PhabricatorDestructibleInterface.php',
|
||||
|
@ -3191,6 +3190,8 @@ phutil_register_library_map(array(
|
|||
'PhabricatorMySQLSearchHost' => 'infrastructure/cluster/search/PhabricatorMySQLSearchHost.php',
|
||||
'PhabricatorMySQLSetupCheck' => 'applications/config/check/PhabricatorMySQLSetupCheck.php',
|
||||
'PhabricatorNamedQuery' => 'applications/search/storage/PhabricatorNamedQuery.php',
|
||||
'PhabricatorNamedQueryConfig' => 'applications/search/storage/PhabricatorNamedQueryConfig.php',
|
||||
'PhabricatorNamedQueryConfigQuery' => 'applications/search/query/PhabricatorNamedQueryConfigQuery.php',
|
||||
'PhabricatorNamedQueryQuery' => 'applications/search/query/PhabricatorNamedQueryQuery.php',
|
||||
'PhabricatorNavigationRemarkupRule' => 'infrastructure/markup/rule/PhabricatorNavigationRemarkupRule.php',
|
||||
'PhabricatorNeverTriggerClock' => 'infrastructure/daemon/workers/clock/PhabricatorNeverTriggerClock.php',
|
||||
|
@ -3214,6 +3215,8 @@ phutil_register_library_map(array(
|
|||
'PhabricatorNotificationTestFeedStory' => 'applications/notification/feed/PhabricatorNotificationTestFeedStory.php',
|
||||
'PhabricatorNotificationUIExample' => 'applications/uiexample/examples/PhabricatorNotificationUIExample.php',
|
||||
'PhabricatorNotificationsApplication' => 'applications/notification/application/PhabricatorNotificationsApplication.php',
|
||||
'PhabricatorNotificationsSetting' => 'applications/settings/setting/PhabricatorNotificationsSetting.php',
|
||||
'PhabricatorNotificationsSettingsPanel' => 'applications/settings/panel/PhabricatorNotificationsSettingsPanel.php',
|
||||
'PhabricatorNuanceApplication' => 'applications/nuance/application/PhabricatorNuanceApplication.php',
|
||||
'PhabricatorOAuth1AuthProvider' => 'applications/auth/provider/PhabricatorOAuth1AuthProvider.php',
|
||||
'PhabricatorOAuth1SecretTemporaryTokenType' => 'applications/auth/provider/PhabricatorOAuth1SecretTemporaryTokenType.php',
|
||||
|
@ -3908,6 +3911,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorSearchDatasourceField' => 'applications/search/field/PhabricatorSearchDatasourceField.php',
|
||||
'PhabricatorSearchDateControlField' => 'applications/search/field/PhabricatorSearchDateControlField.php',
|
||||
'PhabricatorSearchDateField' => 'applications/search/field/PhabricatorSearchDateField.php',
|
||||
'PhabricatorSearchDefaultController' => 'applications/search/controller/PhabricatorSearchDefaultController.php',
|
||||
'PhabricatorSearchDeleteController' => 'applications/search/controller/PhabricatorSearchDeleteController.php',
|
||||
'PhabricatorSearchDocument' => 'applications/search/storage/document/PhabricatorSearchDocument.php',
|
||||
'PhabricatorSearchDocumentField' => 'applications/search/storage/document/PhabricatorSearchDocumentField.php',
|
||||
|
@ -4417,7 +4421,6 @@ phutil_register_library_map(array(
|
|||
'PhamePostTransactionQuery' => 'applications/phame/query/PhamePostTransactionQuery.php',
|
||||
'PhamePostTransactionType' => 'applications/phame/xaction/PhamePostTransactionType.php',
|
||||
'PhamePostViewController' => 'applications/phame/controller/post/PhamePostViewController.php',
|
||||
'PhamePostViewsTransaction' => 'applications/phame/xaction/PhamePostViewsTransaction.php',
|
||||
'PhamePostVisibilityTransaction' => 'applications/phame/xaction/PhamePostVisibilityTransaction.php',
|
||||
'PhameSchemaSpec' => 'applications/phame/storage/PhameSchemaSpec.php',
|
||||
'PhameSite' => 'applications/phame/site/PhameSite.php',
|
||||
|
@ -4881,6 +4884,7 @@ phutil_register_library_map(array(
|
|||
'TokenGiveConduitAPIMethod' => 'applications/tokens/conduit/TokenGiveConduitAPIMethod.php',
|
||||
'TokenGivenConduitAPIMethod' => 'applications/tokens/conduit/TokenGivenConduitAPIMethod.php',
|
||||
'TokenQueryConduitAPIMethod' => 'applications/tokens/conduit/TokenQueryConduitAPIMethod.php',
|
||||
'TransactionSearchConduitAPIMethod' => 'applications/transactions/conduit/TransactionSearchConduitAPIMethod.php',
|
||||
'UserConduitAPIMethod' => 'applications/people/conduit/UserConduitAPIMethod.php',
|
||||
'UserDisableConduitAPIMethod' => 'applications/people/conduit/UserDisableConduitAPIMethod.php',
|
||||
'UserEnableConduitAPIMethod' => 'applications/people/conduit/UserEnableConduitAPIMethod.php',
|
||||
|
@ -5543,6 +5547,7 @@ phutil_register_library_map(array(
|
|||
'DifferentialRevisionHeraldField' => 'HeraldField',
|
||||
'DifferentialRevisionHeraldFieldGroup' => 'HeraldFieldGroup',
|
||||
'DifferentialRevisionIDCommitMessageField' => 'DifferentialCommitMessageField',
|
||||
'DifferentialRevisionInlineTransaction' => 'PhabricatorModularTransactionType',
|
||||
'DifferentialRevisionInlinesController' => 'DifferentialController',
|
||||
'DifferentialRevisionListController' => 'DifferentialController',
|
||||
'DifferentialRevisionListView' => 'AphrontView',
|
||||
|
@ -7952,8 +7957,6 @@ phutil_register_library_map(array(
|
|||
'PhabricatorDebugController' => 'PhabricatorController',
|
||||
'PhabricatorDefaultRequestExceptionHandler' => 'PhabricatorRequestExceptionHandler',
|
||||
'PhabricatorDefaultSyntaxStyle' => 'PhabricatorSyntaxStyle',
|
||||
'PhabricatorDesktopNotificationsSetting' => 'PhabricatorInternalSetting',
|
||||
'PhabricatorDesktopNotificationsSettingsPanel' => 'PhabricatorSettingsPanel',
|
||||
'PhabricatorDestructibleCodex' => 'Phobject',
|
||||
'PhabricatorDestructionEngine' => 'Phobject',
|
||||
'PhabricatorDestructionEngineExtension' => 'Phobject',
|
||||
|
@ -8554,6 +8557,11 @@ phutil_register_library_map(array(
|
|||
'PhabricatorSearchDAO',
|
||||
'PhabricatorPolicyInterface',
|
||||
),
|
||||
'PhabricatorNamedQueryConfig' => array(
|
||||
'PhabricatorSearchDAO',
|
||||
'PhabricatorPolicyInterface',
|
||||
),
|
||||
'PhabricatorNamedQueryConfigQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||
'PhabricatorNamedQueryQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||
'PhabricatorNavigationRemarkupRule' => 'PhutilRemarkupRule',
|
||||
'PhabricatorNeverTriggerClock' => 'PhabricatorTriggerClock',
|
||||
|
@ -8577,6 +8585,8 @@ phutil_register_library_map(array(
|
|||
'PhabricatorNotificationTestFeedStory' => 'PhabricatorFeedStory',
|
||||
'PhabricatorNotificationUIExample' => 'PhabricatorUIExample',
|
||||
'PhabricatorNotificationsApplication' => 'PhabricatorApplication',
|
||||
'PhabricatorNotificationsSetting' => 'PhabricatorInternalSetting',
|
||||
'PhabricatorNotificationsSettingsPanel' => 'PhabricatorSettingsPanel',
|
||||
'PhabricatorNuanceApplication' => 'PhabricatorApplication',
|
||||
'PhabricatorOAuth1AuthProvider' => 'PhabricatorOAuthAuthProvider',
|
||||
'PhabricatorOAuth1SecretTemporaryTokenType' => 'PhabricatorAuthTemporaryTokenType',
|
||||
|
@ -9448,6 +9458,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorSearchDatasourceField' => 'PhabricatorSearchTokenizerField',
|
||||
'PhabricatorSearchDateControlField' => 'PhabricatorSearchField',
|
||||
'PhabricatorSearchDateField' => 'PhabricatorSearchField',
|
||||
'PhabricatorSearchDefaultController' => 'PhabricatorSearchBaseController',
|
||||
'PhabricatorSearchDeleteController' => 'PhabricatorSearchBaseController',
|
||||
'PhabricatorSearchDocument' => 'PhabricatorSearchDAO',
|
||||
'PhabricatorSearchDocumentField' => 'PhabricatorSearchDAO',
|
||||
|
@ -10042,7 +10053,6 @@ phutil_register_library_map(array(
|
|||
'PhamePostTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
||||
'PhamePostTransactionType' => 'PhabricatorModularTransactionType',
|
||||
'PhamePostViewController' => 'PhameLiveController',
|
||||
'PhamePostViewsTransaction' => 'PhamePostTransactionType',
|
||||
'PhamePostVisibilityTransaction' => 'PhamePostTransactionType',
|
||||
'PhameSchemaSpec' => 'PhabricatorConfigSchemaSpec',
|
||||
'PhameSite' => 'PhabricatorSite',
|
||||
|
@ -10622,6 +10632,7 @@ phutil_register_library_map(array(
|
|||
'TokenGiveConduitAPIMethod' => 'TokenConduitAPIMethod',
|
||||
'TokenGivenConduitAPIMethod' => 'TokenConduitAPIMethod',
|
||||
'TokenQueryConduitAPIMethod' => 'TokenConduitAPIMethod',
|
||||
'TransactionSearchConduitAPIMethod' => 'ConduitAPIMethod',
|
||||
'UserConduitAPIMethod' => 'ConduitAPIMethod',
|
||||
'UserDisableConduitAPIMethod' => 'UserConduitAPIMethod',
|
||||
'UserEnableConduitAPIMethod' => 'UserConduitAPIMethod',
|
||||
|
|
|
@ -107,20 +107,6 @@ final class DifferentialTransactionEditor
|
|||
return parent::getCustomTransactionNewValue($object, $xaction);
|
||||
}
|
||||
|
||||
protected function transactionHasEffect(
|
||||
PhabricatorLiskDAO $object,
|
||||
PhabricatorApplicationTransaction $xaction) {
|
||||
|
||||
$actor_phid = $this->getActingAsPHID();
|
||||
|
||||
switch ($xaction->getTransactionType()) {
|
||||
case DifferentialTransaction::TYPE_INLINE:
|
||||
return $xaction->hasComment();
|
||||
}
|
||||
|
||||
return parent::transactionHasEffect($object, $xaction);
|
||||
}
|
||||
|
||||
protected function applyCustomInternalTransaction(
|
||||
PhabricatorLiskDAO $object,
|
||||
PhabricatorApplicationTransaction $xaction) {
|
||||
|
|
|
@ -170,7 +170,7 @@ final class DifferentialChangeset extends DifferentialDAO
|
|||
}
|
||||
|
||||
public function getAnchorName() {
|
||||
return substr(md5($this->getFilename()), 0, 8);
|
||||
return 'change-'.PhabricatorHash::digestForIndex($this->getFilename());
|
||||
}
|
||||
|
||||
public function getAbsoluteRepositoryPath(
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
<?php
|
||||
|
||||
final class DifferentialRevisionInlineTransaction
|
||||
extends PhabricatorModularTransactionType {
|
||||
|
||||
// NOTE: This class is NOT an actual Differential modular transaction type!
|
||||
// It does not extend "DifferentialRevisionTransactionType". Some day it
|
||||
// should, but for now it's just reducing the amount of hackiness around
|
||||
// supporting inline comments in the "transaction.search" Conduit API method.
|
||||
|
||||
const TRANSACTIONTYPE = 'internal.pretend-inline';
|
||||
|
||||
public function getTransactionTypeForConduit($xaction) {
|
||||
return 'inline';
|
||||
}
|
||||
|
||||
public function loadTransactionTypeConduitData(array $xactions) {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$changeset_ids = array();
|
||||
foreach ($xactions as $xaction) {
|
||||
$changeset_ids[] = $xaction->getComment()->getChangesetID();
|
||||
}
|
||||
|
||||
$changesets = id(new DifferentialChangesetQuery())
|
||||
->setViewer($viewer)
|
||||
->withIDs($changeset_ids)
|
||||
->execute();
|
||||
|
||||
$changesets = mpull($changesets, null, 'getID');
|
||||
|
||||
return $changesets;
|
||||
}
|
||||
|
||||
public function getFieldValuesForConduit($object, $data) {
|
||||
$comment = $object->getComment();
|
||||
|
||||
$changeset = $data[$comment->getChangesetID()];
|
||||
$diff = $changeset->getDiff();
|
||||
|
||||
return array(
|
||||
'diff' => array(
|
||||
'id' => (int)$diff->getID(),
|
||||
'phid' => $diff->getPHID(),
|
||||
),
|
||||
'path' => $changeset->getDisplayFilename(),
|
||||
'line' => (int)$comment->getLineNumber(),
|
||||
'length' => (int)($comment->getLineLength() + 1),
|
||||
'replyToCommentPHID' => $comment->getReplyToCommentPHID(),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -70,4 +70,15 @@ final class DifferentialRevisionStatusTransaction
|
|||
return DifferentialRevisionStatus::newForStatus($new);
|
||||
}
|
||||
|
||||
public function getTransactionTypeForConduit($xaction) {
|
||||
return 'status';
|
||||
}
|
||||
|
||||
public function getFieldValuesForConduit($object, $data) {
|
||||
return array(
|
||||
'old' => $object->getOldValue(),
|
||||
'new' => $object->getNewValue(),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -55,4 +55,15 @@ final class DifferentialRevisionTitleTransaction
|
|||
return $errors;
|
||||
}
|
||||
|
||||
public function getTransactionTypeForConduit($xaction) {
|
||||
return 'title';
|
||||
}
|
||||
|
||||
public function getFieldValuesForConduit($object, $data) {
|
||||
return array(
|
||||
'old' => $object->getOldValue(),
|
||||
'new' => $object->getNewValue(),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -706,6 +706,7 @@ final class DiffusionBrowseController extends DiffusionController {
|
|||
|
||||
$buttons[] =
|
||||
id(new PHUIButtonView())
|
||||
->setTag('a')
|
||||
->setText(pht('Last Change'))
|
||||
->setColor(PHUIButtonView::GREY)
|
||||
->setHref(
|
||||
|
@ -1116,7 +1117,6 @@ final class DiffusionBrowseController extends DiffusionController {
|
|||
));
|
||||
}
|
||||
|
||||
$skip_text = pht('Skip Past This Commit');
|
||||
foreach ($display as $line_index => $line) {
|
||||
$row = array();
|
||||
|
||||
|
@ -1132,12 +1132,14 @@ final class DiffusionBrowseController extends DiffusionController {
|
|||
$revision_link = null;
|
||||
$commit_link = null;
|
||||
$before_link = null;
|
||||
$commit_date = null;
|
||||
|
||||
$style = 'background: '.$line['color'].';';
|
||||
$style = 'border-right: 2px solid '.$line['color'].';';
|
||||
|
||||
if ($identifier && !$line['duplicate']) {
|
||||
if (isset($commit_links[$identifier])) {
|
||||
$commit_link = $commit_links[$identifier];
|
||||
$commit_link = $commit_links[$identifier]['link'];
|
||||
$commit_date = $commit_links[$identifier]['date'];
|
||||
}
|
||||
|
||||
if (isset($revision_map[$identifier])) {
|
||||
|
@ -1148,6 +1150,10 @@ final class DiffusionBrowseController extends DiffusionController {
|
|||
}
|
||||
|
||||
$skip_href = $line_href.'?before='.$identifier.'&view=blame';
|
||||
$skip_text = pht('Skip Past This Commit');
|
||||
$icon = id(new PHUIIconView())
|
||||
->setIcon('fa-caret-square-o-left');
|
||||
|
||||
$before_link = javelin_tag(
|
||||
'a',
|
||||
array(
|
||||
|
@ -1159,7 +1165,7 @@ final class DiffusionBrowseController extends DiffusionController {
|
|||
'size' => 300,
|
||||
),
|
||||
),
|
||||
"\xC2\xAB");
|
||||
$icon);
|
||||
}
|
||||
|
||||
if ($show_blame) {
|
||||
|
@ -1170,33 +1176,41 @@ final class DiffusionBrowseController extends DiffusionController {
|
|||
),
|
||||
$before_link);
|
||||
|
||||
$object_links = array();
|
||||
$object_links[] = $commit_link;
|
||||
if ($revision_link) {
|
||||
$object_links[] = phutil_tag('span', array(), '/');
|
||||
$object_links[] = $revision_link;
|
||||
}
|
||||
|
||||
$row[] = phutil_tag(
|
||||
'th',
|
||||
array(
|
||||
'class' => 'diffusion-rev-link',
|
||||
),
|
||||
$object_links);
|
||||
$commit_link);
|
||||
|
||||
if ($revision_map) {
|
||||
$row[] = phutil_tag(
|
||||
'th',
|
||||
array(
|
||||
'class' => 'diffusion-blame-revision',
|
||||
),
|
||||
$revision_link);
|
||||
}
|
||||
|
||||
$row[] = phutil_tag(
|
||||
'th',
|
||||
array(
|
||||
'class' => 'diffusion-blame-date',
|
||||
),
|
||||
$commit_date);
|
||||
}
|
||||
|
||||
$line_link = phutil_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => $line_href,
|
||||
'style' => $style,
|
||||
),
|
||||
$line_number);
|
||||
|
||||
$row[] = javelin_tag(
|
||||
'th',
|
||||
array(
|
||||
'class' => 'diffusion-line-link',
|
||||
'class' => 'diffusion-line-link ',
|
||||
'sigil' => 'phabricator-source-line',
|
||||
'style' => $style,
|
||||
),
|
||||
|
@ -1510,33 +1524,6 @@ final class DiffusionBrowseController extends DiffusionController {
|
|||
return head($parents);
|
||||
}
|
||||
|
||||
private function renderRevisionTooltip(
|
||||
DifferentialRevision $revision,
|
||||
$handles) {
|
||||
$viewer = $this->getRequest()->getUser();
|
||||
|
||||
$date = phabricator_date($revision->getDateModified(), $viewer);
|
||||
$id = $revision->getID();
|
||||
$title = $revision->getTitle();
|
||||
$header = "D{$id} {$title}";
|
||||
|
||||
$author = $handles[$revision->getAuthorPHID()]->getName();
|
||||
|
||||
return "{$header}\n{$date} \xC2\xB7 {$author}";
|
||||
}
|
||||
|
||||
private function renderCommitTooltip(
|
||||
PhabricatorRepositoryCommit $commit,
|
||||
$author) {
|
||||
|
||||
$viewer = $this->getRequest()->getUser();
|
||||
|
||||
$date = phabricator_date($commit->getEpoch(), $viewer);
|
||||
$summary = trim($commit->getSummary());
|
||||
|
||||
return "{$summary}\n{$date} \xC2\xB7 {$author}";
|
||||
}
|
||||
|
||||
protected function markupText($text) {
|
||||
$engine = PhabricatorMarkupEngine::newDiffusionMarkupEngine();
|
||||
$engine->setConfig('viewer', $this->getRequest()->getUser());
|
||||
|
@ -1617,6 +1604,7 @@ final class DiffusionBrowseController extends DiffusionController {
|
|||
$head = null;
|
||||
if ($behind_head) {
|
||||
$head = id(new PHUIButtonView())
|
||||
->setTag('a')
|
||||
->setText(pht('Back to HEAD'))
|
||||
->setHref($head_uri)
|
||||
->setIcon('fa-home')
|
||||
|
@ -1737,9 +1725,6 @@ final class DiffusionBrowseController extends DiffusionController {
|
|||
->setViewer($viewer)
|
||||
->withRepository($repository)
|
||||
->withIdentifiers($identifiers)
|
||||
// TODO: We only fetch this to improve author display behavior, but
|
||||
// shouldn't really need to?
|
||||
->needCommitData(true)
|
||||
->execute();
|
||||
$commits = mpull($commits, null, 'getCommitIdentifier');
|
||||
} else {
|
||||
|
@ -1751,25 +1736,27 @@ final class DiffusionBrowseController extends DiffusionController {
|
|||
|
||||
private function renderCommitLinks(array $commits, $handles) {
|
||||
$links = array();
|
||||
$viewer = $this->getViewer();
|
||||
foreach ($commits as $identifier => $commit) {
|
||||
$tooltip = $this->renderCommitTooltip(
|
||||
$commit,
|
||||
$commit->renderAuthorShortName($handles));
|
||||
$date = phabricator_date($commit->getEpoch(), $viewer);
|
||||
$summary = trim($commit->getSummary());
|
||||
|
||||
$commit_link = javelin_tag(
|
||||
$commit_link = phutil_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => $commit->getURI(),
|
||||
'sigil' => 'has-tooltip',
|
||||
'meta' => array(
|
||||
'tip' => $tooltip,
|
||||
'align' => 'E',
|
||||
'size' => 600,
|
||||
),
|
||||
),
|
||||
$commit->getLocalName());
|
||||
$summary);
|
||||
|
||||
$links[$identifier] = $commit_link;
|
||||
$commit_date = phutil_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => $commit->getURI(),
|
||||
),
|
||||
$date);
|
||||
|
||||
$links[$identifier]['link'] = $commit_link;
|
||||
$links[$identifier]['date'] = $commit_date;
|
||||
}
|
||||
|
||||
return $links;
|
||||
|
@ -1780,19 +1767,10 @@ final class DiffusionBrowseController extends DiffusionController {
|
|||
|
||||
foreach ($revisions as $revision) {
|
||||
$revision_id = $revision->getID();
|
||||
|
||||
$tooltip = $this->renderRevisionTooltip($revision, $handles);
|
||||
|
||||
$revision_link = javelin_tag(
|
||||
$revision_link = phutil_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => '/'.$revision->getMonogram(),
|
||||
'sigil' => 'has-tooltip',
|
||||
'meta' => array(
|
||||
'tip' => $tooltip,
|
||||
'align' => 'E',
|
||||
'size' => 600,
|
||||
),
|
||||
),
|
||||
$revision->getMonogram());
|
||||
|
||||
|
|
|
@ -251,6 +251,56 @@ EODOCS
|
|||
id(new PHUIRemarkupPreviewPanel())
|
||||
->setHeader(pht('Description Preview')));
|
||||
|
||||
$parent_type = ManiphestTaskDependedOnByTaskEdgeType::EDGECONST;
|
||||
$subtask_type = ManiphestTaskDependsOnTaskEdgeType::EDGECONST;
|
||||
|
||||
$src_phid = $object->getPHID();
|
||||
if ($src_phid) {
|
||||
$edge_query = id(new PhabricatorEdgeQuery())
|
||||
->withSourcePHIDs(array($src_phid))
|
||||
->withEdgeTypes(
|
||||
array(
|
||||
$parent_type,
|
||||
$subtask_type,
|
||||
));
|
||||
$edge_query->execute();
|
||||
|
||||
$parent_phids = $edge_query->getDestinationPHIDs(
|
||||
array($src_phid),
|
||||
array($parent_type));
|
||||
|
||||
$subtask_phids = $edge_query->getDestinationPHIDs(
|
||||
array($src_phid),
|
||||
array($subtask_type));
|
||||
} else {
|
||||
$parent_phids = array();
|
||||
$subtask_phids = array();
|
||||
}
|
||||
|
||||
$fields[] = id(new PhabricatorHandlesEditField())
|
||||
->setKey('parents')
|
||||
->setLabel(pht('Parents'))
|
||||
->setDescription(pht('Parent tasks.'))
|
||||
->setConduitDescription(pht('Change the parents of this task.'))
|
||||
->setConduitTypeDescription(pht('List of parent task PHIDs.'))
|
||||
->setUseEdgeTransactions(true)
|
||||
->setIsConduitOnly(true)
|
||||
->setTransactionType(PhabricatorTransactions::TYPE_EDGE)
|
||||
->setMetadataValue('edge:type', $parent_type)
|
||||
->setValue($parent_phids);
|
||||
|
||||
$fields[] = id(new PhabricatorHandlesEditField())
|
||||
->setKey('subtasks')
|
||||
->setLabel(pht('Subtasks'))
|
||||
->setDescription(pht('Subtasks.'))
|
||||
->setConduitDescription(pht('Change the subtasks of this task.'))
|
||||
->setConduitTypeDescription(pht('List of subtask PHIDs.'))
|
||||
->setUseEdgeTransactions(true)
|
||||
->setIsConduitOnly(true)
|
||||
->setTransactionType(PhabricatorTransactions::TYPE_EDGE)
|
||||
->setMetadataValue('edge:type', $subtask_type)
|
||||
->setValue($parent_phids);
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
|
|
|
@ -236,8 +236,6 @@ final class ManiphestTaskSearchEngine
|
|||
$group = idx($this->getGroupValues(), $group);
|
||||
if ($group) {
|
||||
$query->setGroupBy($group);
|
||||
} else {
|
||||
$query->setGroupBy(head($this->getGroupValues()));
|
||||
}
|
||||
|
||||
if ($map['ids']) {
|
||||
|
|
|
@ -145,13 +145,16 @@ final class PhabricatorNotificationBuilder extends Phobject {
|
|||
$dict = array();
|
||||
|
||||
$viewer = $this->user;
|
||||
$desktop_key = PhabricatorDesktopNotificationsSetting::SETTINGKEY;
|
||||
$desktop_enabled = $viewer->getUserSetting($desktop_key);
|
||||
$key = PhabricatorNotificationsSetting::SETTINGKEY;
|
||||
$setting = $viewer->getUserSetting($key);
|
||||
$desktop_ready = PhabricatorNotificationsSetting::desktopReady($setting);
|
||||
$web_ready = PhabricatorNotificationsSetting::webReady($setting);
|
||||
|
||||
foreach ($stories as $story) {
|
||||
if ($story instanceof PhabricatorApplicationTransactionFeedStory) {
|
||||
$dict[] = array(
|
||||
'desktopReady' => $desktop_enabled,
|
||||
'desktopReady' => $desktop_ready,
|
||||
'webReady' => $web_ready,
|
||||
'title' => $story->renderText(),
|
||||
'body' => $story->renderTextBody(),
|
||||
'href' => $story->getURI(),
|
||||
|
@ -159,7 +162,8 @@ final class PhabricatorNotificationBuilder extends Phobject {
|
|||
);
|
||||
} else if ($story instanceof PhabricatorNotificationTestFeedStory) {
|
||||
$dict[] = array(
|
||||
'desktopReady' => $desktop_enabled,
|
||||
'desktopReady' => $desktop_ready,
|
||||
'webReady' => $web_ready,
|
||||
'title' => pht('Test Notification'),
|
||||
'body' => $story->renderText(),
|
||||
'href' => null,
|
||||
|
@ -168,6 +172,7 @@ final class PhabricatorNotificationBuilder extends Phobject {
|
|||
} else {
|
||||
$dict[] = array(
|
||||
'desktopReady' => false,
|
||||
'webReady' => false,
|
||||
'title' => null,
|
||||
'body' => null,
|
||||
'href' => null,
|
||||
|
|
|
@ -42,6 +42,7 @@ final class PhabricatorNotificationIndividualController
|
|||
'pertinent' => true,
|
||||
'primaryObjectPHID' => $story->getPrimaryObjectPHID(),
|
||||
'desktopReady' => $data['desktopReady'],
|
||||
'webReady' => $data['webReady'],
|
||||
'href' => $data['href'],
|
||||
'icon' => $data['icon'],
|
||||
'title' => $data['title'],
|
||||
|
|
|
@ -18,25 +18,6 @@ final class PhamePostViewController
|
|||
$is_live = $this->getIsLive();
|
||||
$is_external = $this->getIsExternal();
|
||||
|
||||
// Register a blog "view" count
|
||||
//
|
||||
if (!$post->isDraft() && !$post->isArchived()) {
|
||||
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
|
||||
$xactions = array();
|
||||
$xactions[] = id(new PhamePostTransaction())
|
||||
->setTransactionType(PhamePostViewsTransaction::TRANSACTIONTYPE)
|
||||
->setNewValue(null);
|
||||
|
||||
$editor = id(new PhamePostEditor())
|
||||
->setActor($viewer)
|
||||
->setContentSourceFromRequest($request)
|
||||
->setContinueOnMissingFields(true)
|
||||
->setContinueOnNoEffect(true);
|
||||
|
||||
$editor->applyTransactions($post, $xactions);
|
||||
unset($unguarded);
|
||||
}
|
||||
|
||||
$header = id(new PHUIHeaderView())
|
||||
->addClass('phame-header-bar')
|
||||
->setUser($viewer);
|
||||
|
@ -170,11 +151,6 @@ final class PhamePostViewController
|
|||
->setUser($viewer)
|
||||
->setObject($post);
|
||||
|
||||
$views = id(new PhutilNumber($post->getViews()));
|
||||
$properties->addProperty(
|
||||
pht('Views'),
|
||||
pht('%s', $views));
|
||||
|
||||
$is_live = $this->getIsLive();
|
||||
$is_external = $this->getIsExternal();
|
||||
$next_view = new PhameNextPostView();
|
||||
|
|
|
@ -41,12 +41,6 @@ final class PhamePostEditor
|
|||
if ($object->isDraft() || $object->isArchived()) {
|
||||
return false;
|
||||
}
|
||||
foreach ($xactions as $xaction) {
|
||||
switch ($xaction->getTransactionType()) {
|
||||
case PhamePostViewsTransaction::TRANSACTIONTYPE:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,6 @@ final class PhamePost extends PhameDAO
|
|||
protected $phameTitle;
|
||||
protected $body;
|
||||
protected $visibility;
|
||||
protected $views;
|
||||
protected $configData;
|
||||
protected $datePublished;
|
||||
protected $blogPHID;
|
||||
|
@ -41,8 +40,7 @@ final class PhamePost extends PhameDAO
|
|||
->setBlogPHID($blog->getPHID())
|
||||
->attachBlog($blog)
|
||||
->setDatePublished(PhabricatorTime::getNow())
|
||||
->setVisibility(PhameConstants::VISIBILITY_PUBLISHED)
|
||||
->setViews(0);
|
||||
->setVisibility(PhameConstants::VISIBILITY_PUBLISHED);
|
||||
|
||||
return $post;
|
||||
}
|
||||
|
@ -130,7 +128,6 @@ final class PhamePost extends PhameDAO
|
|||
'subtitle' => 'text64',
|
||||
'phameTitle' => 'sort64?',
|
||||
'visibility' => 'uint32',
|
||||
'views' => 'uint32',
|
||||
'mailKey' => 'bytes20',
|
||||
'headerImagePHID' => 'phid?',
|
||||
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class PhamePostViewsTransaction
|
||||
extends PhamePostTransactionType {
|
||||
|
||||
const TRANSACTIONTYPE = 'phame.post.views';
|
||||
|
||||
public function generateOldValue($object) {
|
||||
return $object->getViews();
|
||||
}
|
||||
|
||||
public function applyInternalEffects($object, $value) {
|
||||
$views = $object->getViews();
|
||||
$views++;
|
||||
$object->setViews($views);
|
||||
}
|
||||
|
||||
}
|
|
@ -33,9 +33,18 @@ final class PhabricatorSearchApplication extends PhabricatorApplication {
|
|||
'index/(?P<phid>[^/]+)/' => 'PhabricatorSearchIndexController',
|
||||
'hovercard/'
|
||||
=> 'PhabricatorSearchHovercardController',
|
||||
'edit/(?P<queryKey>[^/]+)/' => 'PhabricatorSearchEditController',
|
||||
'delete/(?P<queryKey>[^/]+)/(?P<engine>[^/]+)/'
|
||||
'edit/' => array(
|
||||
'key/(?P<queryKey>[^/]+)/' => 'PhabricatorSearchEditController',
|
||||
'id/(?P<id>[^/]+)/' => 'PhabricatorSearchEditController',
|
||||
),
|
||||
'default/(?P<queryKey>[^/]+)/(?P<engine>[^/]+)/'
|
||||
=> 'PhabricatorSearchDefaultController',
|
||||
'delete/' => array(
|
||||
'key/(?P<queryKey>[^/]+)/(?P<engine>[^/]+)/'
|
||||
=> 'PhabricatorSearchDeleteController',
|
||||
'id/(?P<id>[^/]+)/'
|
||||
=> 'PhabricatorSearchDeleteController',
|
||||
),
|
||||
'order/(?P<engine>[^/]+)/' => 'PhabricatorSearchOrderController',
|
||||
'rel/(?P<relationshipKey>[^/]+)/(?P<sourcePHID>[^/]+)/'
|
||||
=> 'PhabricatorSearchRelationshipController',
|
||||
|
|
|
@ -127,7 +127,7 @@ final class PhabricatorApplicationSearchController
|
|||
if (!$found_query_data) {
|
||||
// Otherwise, there's no query data so just run the user's default
|
||||
// query for this application.
|
||||
$query_key = head_key($engine->loadEnabledNamedQueries());
|
||||
$query_key = $engine->getDefaultQueryKey();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -174,7 +174,7 @@ final class PhabricatorApplicationSearchController
|
|||
if ($run_query && !$named_query && $user->isLoggedIn()) {
|
||||
$save_button = id(new PHUIButtonView())
|
||||
->setTag('a')
|
||||
->setHref('/search/edit/'.$saved_query->getQueryKey().'/')
|
||||
->setHref('/search/edit/key/'.$saved_query->getQueryKey().'/')
|
||||
->setText(pht('Save Query'))
|
||||
->setIcon('fa-floppy-o');
|
||||
$submit->addButton($save_button);
|
||||
|
@ -377,7 +377,7 @@ final class PhabricatorApplicationSearchController
|
|||
private function processEditRequest() {
|
||||
$parent = $this->getDelegatingController();
|
||||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
$viewer = $request->getUser();
|
||||
$engine = $this->getSearchEngine();
|
||||
|
||||
$nav = $this->getNavigation();
|
||||
|
@ -387,65 +387,42 @@ final class PhabricatorApplicationSearchController
|
|||
|
||||
$named_queries = $engine->loadAllNamedQueries();
|
||||
|
||||
$list_id = celerity_generate_unique_node_id();
|
||||
$can_global = $viewer->getIsAdmin();
|
||||
|
||||
$list = new PHUIObjectItemListView();
|
||||
$list->setUser($user);
|
||||
$list->setID($list_id);
|
||||
|
||||
Javelin::initBehavior(
|
||||
'search-reorder-queries',
|
||||
array(
|
||||
'listID' => $list_id,
|
||||
'orderURI' => '/search/order/'.get_class($engine).'/',
|
||||
));
|
||||
$groups = array(
|
||||
'personal' => array(
|
||||
'name' => pht('Personal Saved Queries'),
|
||||
'items' => array(),
|
||||
'edit' => true,
|
||||
),
|
||||
'global' => array(
|
||||
'name' => pht('Global Saved Queries'),
|
||||
'items' => array(),
|
||||
'edit' => $can_global,
|
||||
),
|
||||
);
|
||||
|
||||
foreach ($named_queries as $named_query) {
|
||||
$class = get_class($engine);
|
||||
$key = $named_query->getQueryKey();
|
||||
|
||||
$item = id(new PHUIObjectItemView())
|
||||
->setHeader($named_query->getQueryName())
|
||||
->setHref($engine->getQueryResultsPageURI($key));
|
||||
|
||||
if ($named_query->getIsBuiltin() && $named_query->getIsDisabled()) {
|
||||
$icon = 'fa-plus';
|
||||
if ($named_query->isGlobal()) {
|
||||
$group = 'global';
|
||||
} else {
|
||||
$icon = 'fa-times';
|
||||
$group = 'personal';
|
||||
}
|
||||
|
||||
$item->addAction(
|
||||
id(new PHUIListItemView())
|
||||
->setIcon($icon)
|
||||
->setHref('/search/delete/'.$key.'/'.$class.'/')
|
||||
->setWorkflow(true));
|
||||
|
||||
if ($named_query->getIsBuiltin()) {
|
||||
if ($named_query->getIsDisabled()) {
|
||||
$item->addIcon('fa-times lightgreytext', pht('Disabled'));
|
||||
$item->setDisabled(true);
|
||||
} else {
|
||||
$item->addIcon('fa-lock lightgreytext', pht('Builtin'));
|
||||
}
|
||||
} else {
|
||||
$item->addAction(
|
||||
id(new PHUIListItemView())
|
||||
->setIcon('fa-pencil')
|
||||
->setHref('/search/edit/'.$key.'/'));
|
||||
$groups[$group]['items'][] = $named_query;
|
||||
}
|
||||
|
||||
$item->setGrippable(true);
|
||||
$item->addSigil('named-query');
|
||||
$item->setMetadata(
|
||||
array(
|
||||
'queryKey' => $named_query->getQueryKey(),
|
||||
));
|
||||
$default_key = $engine->getDefaultQueryKey();
|
||||
|
||||
$list->addItem($item);
|
||||
$lists = array();
|
||||
foreach ($groups as $group) {
|
||||
$lists[] = $this->newQueryListView(
|
||||
$group['name'],
|
||||
$group['items'],
|
||||
$default_key,
|
||||
$group['edit']);
|
||||
}
|
||||
|
||||
$list->setNoDataString(pht('No saved queries.'));
|
||||
|
||||
$crumbs = $parent
|
||||
->buildApplicationCrumbs()
|
||||
->addTextCrumb(pht('Saved Queries'), $engine->getQueryManagementURI())
|
||||
|
@ -457,20 +434,144 @@ final class PhabricatorApplicationSearchController
|
|||
->setHeader(pht('Saved Queries'))
|
||||
->setProfileHeader(true);
|
||||
|
||||
$box = id(new PHUIObjectBoxView())
|
||||
$view = id(new PHUITwoColumnView())
|
||||
->setHeader($header)
|
||||
->setObjectList($list)
|
||||
->addClass('application-search-results');
|
||||
|
||||
$nav->addClass('application-search-view');
|
||||
require_celerity_resource('application-search-view-css');
|
||||
->setFooter($lists);
|
||||
|
||||
return $this->newPage()
|
||||
->setApplicationMenu($this->buildApplicationMenu())
|
||||
->setTitle(pht('Saved Queries'))
|
||||
->setCrumbs($crumbs)
|
||||
->setNavigation($nav)
|
||||
->appendChild($box);
|
||||
->appendChild($view);
|
||||
}
|
||||
|
||||
private function newQueryListView(
|
||||
$list_name,
|
||||
array $named_queries,
|
||||
$default_key,
|
||||
$can_edit) {
|
||||
|
||||
$engine = $this->getSearchEngine();
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$list = id(new PHUIObjectItemListView())
|
||||
->setViewer($viewer);
|
||||
|
||||
if ($can_edit) {
|
||||
$list_id = celerity_generate_unique_node_id();
|
||||
$list->setID($list_id);
|
||||
|
||||
Javelin::initBehavior(
|
||||
'search-reorder-queries',
|
||||
array(
|
||||
'listID' => $list_id,
|
||||
'orderURI' => '/search/order/'.get_class($engine).'/',
|
||||
));
|
||||
}
|
||||
|
||||
foreach ($named_queries as $named_query) {
|
||||
$class = get_class($engine);
|
||||
$key = $named_query->getQueryKey();
|
||||
|
||||
$item = id(new PHUIObjectItemView())
|
||||
->setHeader($named_query->getQueryName())
|
||||
->setHref($engine->getQueryResultsPageURI($key));
|
||||
|
||||
if ($named_query->getIsDisabled()) {
|
||||
if ($can_edit) {
|
||||
$item->setDisabled(true);
|
||||
} else {
|
||||
// If an item is disabled and you don't have permission to edit it,
|
||||
// just skip it.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if ($can_edit) {
|
||||
if ($named_query->getIsBuiltin() && $named_query->getIsDisabled()) {
|
||||
$icon = 'fa-plus';
|
||||
$disable_name = pht('Enable');
|
||||
} else {
|
||||
$icon = 'fa-times';
|
||||
if ($named_query->getIsBuiltin()) {
|
||||
$disable_name = pht('Disable');
|
||||
} else {
|
||||
$disable_name = pht('Delete');
|
||||
}
|
||||
}
|
||||
|
||||
if ($named_query->getID()) {
|
||||
$disable_href = '/search/delete/id/'.$named_query->getID().'/';
|
||||
} else {
|
||||
$disable_href = '/search/delete/key/'.$key.'/'.$class.'/';
|
||||
}
|
||||
|
||||
$item->addAction(
|
||||
id(new PHUIListItemView())
|
||||
->setIcon($icon)
|
||||
->setHref($disable_href)
|
||||
->setRenderNameAsTooltip(true)
|
||||
->setName($disable_name)
|
||||
->setWorkflow(true));
|
||||
}
|
||||
|
||||
$default_disabled = $named_query->getIsDisabled();
|
||||
$default_icon = 'fa-thumb-tack';
|
||||
|
||||
if ($default_key === $key) {
|
||||
$default_color = 'green';
|
||||
} else {
|
||||
$default_color = null;
|
||||
}
|
||||
|
||||
$item->addAction(
|
||||
id(new PHUIListItemView())
|
||||
->setIcon("{$default_icon} {$default_color}")
|
||||
->setHref('/search/default/'.$key.'/'.$class.'/')
|
||||
->setRenderNameAsTooltip(true)
|
||||
->setName(pht('Make Default'))
|
||||
->setWorkflow(true)
|
||||
->setDisabled($default_disabled));
|
||||
|
||||
if ($can_edit) {
|
||||
if ($named_query->getIsBuiltin()) {
|
||||
$edit_icon = 'fa-lock lightgreytext';
|
||||
$edit_disabled = true;
|
||||
$edit_name = pht('Builtin');
|
||||
$edit_href = null;
|
||||
} else {
|
||||
$edit_icon = 'fa-pencil';
|
||||
$edit_disabled = false;
|
||||
$edit_name = pht('Edit');
|
||||
$edit_href = '/search/edit/id/'.$named_query->getID().'/';
|
||||
}
|
||||
|
||||
$item->addAction(
|
||||
id(new PHUIListItemView())
|
||||
->setIcon($edit_icon)
|
||||
->setHref($edit_href)
|
||||
->setRenderNameAsTooltip(true)
|
||||
->setName($edit_name)
|
||||
->setDisabled($edit_disabled));
|
||||
}
|
||||
|
||||
$item->setGrippable($can_edit);
|
||||
$item->addSigil('named-query');
|
||||
$item->setMetadata(
|
||||
array(
|
||||
'queryKey' => $named_query->getQueryKey(),
|
||||
));
|
||||
|
||||
$list->addItem($item);
|
||||
}
|
||||
|
||||
$list->setNoDataString(pht('No saved queries.'));
|
||||
|
||||
return id(new PHUIObjectBoxView())
|
||||
->setHeaderText($list_name)
|
||||
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
||||
->setObjectList($list);
|
||||
}
|
||||
|
||||
public function buildApplicationMenu() {
|
||||
|
@ -610,7 +711,7 @@ final class PhabricatorApplicationSearchController
|
|||
$engine_class = get_class($engine);
|
||||
$query_key = $this->getQueryKey();
|
||||
if (!$query_key) {
|
||||
$query_key = head_key($engine->loadEnabledNamedQueries());
|
||||
$query_key = $engine->getDefaultQueryKey();
|
||||
}
|
||||
|
||||
$can_use = $engine->canUseInPanelContext();
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorSearchDefaultController
|
||||
extends PhabricatorSearchBaseController {
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$viewer = $this->getViewer();
|
||||
$engine_class = $request->getURIData('engine');
|
||||
|
||||
$base_class = 'PhabricatorApplicationSearchEngine';
|
||||
if (!is_subclass_of($engine_class, $base_class)) {
|
||||
return new Aphront400Response();
|
||||
}
|
||||
|
||||
$engine = newv($engine_class, array());
|
||||
$engine->setViewer($viewer);
|
||||
|
||||
$key = $request->getURIData('queryKey');
|
||||
|
||||
$named_query = id(new PhabricatorNamedQueryQuery())
|
||||
->setViewer($viewer)
|
||||
->withEngineClassNames(array($engine_class))
|
||||
->withQueryKeys(array($key))
|
||||
->withUserPHIDs(
|
||||
array(
|
||||
$viewer->getPHID(),
|
||||
PhabricatorNamedQuery::SCOPE_GLOBAL,
|
||||
))
|
||||
->executeOne();
|
||||
|
||||
if (!$named_query && $engine->isBuiltinQuery($key)) {
|
||||
$named_query = $engine->getBuiltinQuery($key);
|
||||
}
|
||||
|
||||
if (!$named_query) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$return_uri = $engine->getQueryManagementURI();
|
||||
|
||||
$builtin = null;
|
||||
if ($engine->isBuiltinQuery($key)) {
|
||||
$builtin = $engine->getBuiltinQuery($key);
|
||||
}
|
||||
|
||||
if ($request->isFormPost()) {
|
||||
$config = id(new PhabricatorNamedQueryConfigQuery())
|
||||
->setViewer($viewer)
|
||||
->withEngineClassNames(array($engine_class))
|
||||
->withScopePHIDs(array($viewer->getPHID()))
|
||||
->executeOne();
|
||||
if (!$config) {
|
||||
$config = PhabricatorNamedQueryConfig::initializeNewQueryConfig()
|
||||
->setEngineClassName($engine_class)
|
||||
->setScopePHID($viewer->getPHID());
|
||||
}
|
||||
|
||||
$config->setConfigProperty(
|
||||
PhabricatorNamedQueryConfig::PROPERTY_PINNED,
|
||||
$key);
|
||||
|
||||
$config->save();
|
||||
|
||||
return id(new AphrontRedirectResponse())->setURI($return_uri);
|
||||
}
|
||||
|
||||
if ($named_query->getIsBuiltin()) {
|
||||
$query_name = $builtin->getQueryName();
|
||||
} else {
|
||||
$query_name = $named_query->getQueryName();
|
||||
}
|
||||
|
||||
$title = pht('Set Default Query');
|
||||
$body = pht(
|
||||
'This query will become your default query in the current application.');
|
||||
$button = pht('Set Default Query');
|
||||
|
||||
return $this->newDialog()
|
||||
->setTitle($title)
|
||||
->appendChild($body)
|
||||
->addCancelButton($return_uri)
|
||||
->addSubmitButton($button);
|
||||
}
|
||||
|
||||
}
|
|
@ -5,6 +5,27 @@ final class PhabricatorSearchDeleteController
|
|||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$id = $request->getURIData('id');
|
||||
if ($id) {
|
||||
$named_query = id(new PhabricatorNamedQueryQuery())
|
||||
->setViewer($viewer)
|
||||
->withIDs(array($id))
|
||||
->requireCapabilities(
|
||||
array(
|
||||
PhabricatorPolicyCapability::CAN_VIEW,
|
||||
PhabricatorPolicyCapability::CAN_EDIT,
|
||||
))
|
||||
->executeOne();
|
||||
if (!$named_query) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$engine = newv($named_query->getEngineClassName(), array());
|
||||
$engine->setViewer($viewer);
|
||||
|
||||
$key = $named_query->getQueryKey();
|
||||
} else {
|
||||
$key = $request->getURIData('queryKey');
|
||||
$engine_class = $request->getURIData('engine');
|
||||
|
||||
|
@ -16,19 +37,11 @@ final class PhabricatorSearchDeleteController
|
|||
$engine = newv($engine_class, array());
|
||||
$engine->setViewer($viewer);
|
||||
|
||||
$named_query = id(new PhabricatorNamedQueryQuery())
|
||||
->setViewer($viewer)
|
||||
->withEngineClassNames(array($engine_class))
|
||||
->withQueryKeys(array($key))
|
||||
->withUserPHIDs(array($viewer->getPHID()))
|
||||
->executeOne();
|
||||
|
||||
if (!$named_query && $engine->isBuiltinQuery($key)) {
|
||||
$named_query = $engine->getBuiltinQuery($key);
|
||||
if (!$engine->isBuiltinQuery($key)) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
if (!$named_query) {
|
||||
return new Aphront404Response();
|
||||
$named_query = $engine->getBuiltinQuery($key);
|
||||
}
|
||||
|
||||
$builtin = null;
|
||||
|
|
|
@ -6,11 +6,31 @@ final class PhabricatorSearchEditController
|
|||
public function handleRequest(AphrontRequest $request) {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$id = $request->getURIData('id');
|
||||
if ($id) {
|
||||
$named_query = id(new PhabricatorNamedQueryQuery())
|
||||
->setViewer($viewer)
|
||||
->withIDs(array($id))
|
||||
->requireCapabilities(
|
||||
array(
|
||||
PhabricatorPolicyCapability::CAN_VIEW,
|
||||
PhabricatorPolicyCapability::CAN_EDIT,
|
||||
))
|
||||
->executeOne();
|
||||
if (!$named_query) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$query_key = $named_query->getQueryKey();
|
||||
} else {
|
||||
$query_key = $request->getURIData('queryKey');
|
||||
$named_query = null;
|
||||
}
|
||||
|
||||
$saved_query = id(new PhabricatorSavedQueryQuery())
|
||||
->setViewer($viewer)
|
||||
->withQueryKeys(array($request->getURIData('queryKey')))
|
||||
->withQueryKeys(array($query_key))
|
||||
->executeOne();
|
||||
|
||||
if (!$saved_query) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
@ -20,11 +40,6 @@ final class PhabricatorSearchEditController
|
|||
$complete_uri = $engine->getQueryManagementURI();
|
||||
$cancel_uri = $complete_uri;
|
||||
|
||||
$named_query = id(new PhabricatorNamedQueryQuery())
|
||||
->setViewer($viewer)
|
||||
->withQueryKeys(array($saved_query->getQueryKey()))
|
||||
->withUserPHIDs(array($viewer->getPHID()))
|
||||
->executeOne();
|
||||
if (!$named_query) {
|
||||
$named_query = id(new PhabricatorNamedQuery())
|
||||
->setUserPHID($viewer->getPHID())
|
||||
|
@ -36,12 +51,27 @@ final class PhabricatorSearchEditController
|
|||
// management interface.
|
||||
$cancel_uri = $engine->getQueryResultsPageURI(
|
||||
$saved_query->getQueryKey());
|
||||
|
||||
$is_new = true;
|
||||
} else {
|
||||
$is_new = false;
|
||||
}
|
||||
|
||||
$can_global = ($viewer->getIsAdmin() && $is_new);
|
||||
|
||||
$v_global = false;
|
||||
|
||||
$e_name = true;
|
||||
$errors = array();
|
||||
|
||||
if ($request->isFormPost()) {
|
||||
if ($can_global) {
|
||||
$v_global = $request->getBool('global');
|
||||
if ($v_global) {
|
||||
$named_query->setUserPHID(PhabricatorNamedQuery::SCOPE_GLOBAL);
|
||||
}
|
||||
}
|
||||
|
||||
$named_query->setQueryName($request->getStr('name'));
|
||||
if (!strlen($named_query->getQueryName())) {
|
||||
$e_name = pht('Required');
|
||||
|
@ -51,6 +81,7 @@ final class PhabricatorSearchEditController
|
|||
}
|
||||
|
||||
if (!$errors) {
|
||||
|
||||
$named_query->save();
|
||||
return id(new AphrontRedirectResponse())->setURI($complete_uri);
|
||||
}
|
||||
|
@ -66,6 +97,18 @@ final class PhabricatorSearchEditController
|
|||
->setValue($named_query->getQueryName())
|
||||
->setError($e_name));
|
||||
|
||||
if ($can_global) {
|
||||
$form->appendChild(
|
||||
id(new AphrontFormCheckboxControl())
|
||||
->addCheckbox(
|
||||
'global',
|
||||
'1',
|
||||
pht(
|
||||
'Save this query as a global query, making it visible to '.
|
||||
'all users.'),
|
||||
$v_global));
|
||||
}
|
||||
|
||||
$form->appendChild(
|
||||
id(new AphrontFormSubmitControl())
|
||||
->setValue(pht('Save Query'))
|
||||
|
|
|
@ -474,8 +474,12 @@ abstract class PhabricatorApplicationSearchEngine extends Phobject {
|
|||
if ($this->namedQueries === null) {
|
||||
$named_queries = id(new PhabricatorNamedQueryQuery())
|
||||
->setViewer($viewer)
|
||||
->withUserPHIDs(array($viewer->getPHID()))
|
||||
->withEngineClassNames(array(get_class($this)))
|
||||
->withUserPHIDs(
|
||||
array(
|
||||
$viewer->getPHID(),
|
||||
PhabricatorNamedQuery::SCOPE_GLOBAL,
|
||||
))
|
||||
->execute();
|
||||
$named_queries = mpull($named_queries, null, 'getQueryKey');
|
||||
|
||||
|
@ -494,7 +498,7 @@ abstract class PhabricatorApplicationSearchEngine extends Phobject {
|
|||
unset($builtin[$key]);
|
||||
}
|
||||
|
||||
$named_queries = msort($named_queries, 'getSortKey');
|
||||
$named_queries = msortv($named_queries, 'getNamedQuerySortVector');
|
||||
$this->namedQueries = $named_queries;
|
||||
}
|
||||
|
||||
|
@ -511,6 +515,34 @@ abstract class PhabricatorApplicationSearchEngine extends Phobject {
|
|||
return $named_queries;
|
||||
}
|
||||
|
||||
public function getDefaultQueryKey() {
|
||||
$viewer = $this->requireViewer();
|
||||
|
||||
$configs = id(new PhabricatorNamedQueryConfigQuery())
|
||||
->setViewer($viewer)
|
||||
->withEngineClassNames(array(get_class($this)))
|
||||
->withScopePHIDs(
|
||||
array(
|
||||
$viewer->getPHID(),
|
||||
PhabricatorNamedQueryConfig::SCOPE_GLOBAL,
|
||||
))
|
||||
->execute();
|
||||
$configs = msortv($configs, 'getStrengthSortVector');
|
||||
|
||||
$key_pinned = PhabricatorNamedQueryConfig::PROPERTY_PINNED;
|
||||
$map = $this->loadEnabledNamedQueries();
|
||||
foreach ($configs as $config) {
|
||||
$pinned = $config->getConfigProperty($key_pinned);
|
||||
if (!isset($map[$pinned])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return $pinned;
|
||||
}
|
||||
|
||||
return head_key($map);
|
||||
}
|
||||
|
||||
protected function setQueryProjects(
|
||||
PhabricatorCursorPagedPolicyAwareQuery $query,
|
||||
PhabricatorSavedQuery $saved) {
|
||||
|
@ -603,7 +635,7 @@ abstract class PhabricatorApplicationSearchEngine extends Phobject {
|
|||
$sequence = 0;
|
||||
foreach ($names as $key => $name) {
|
||||
$queries[$key] = id(new PhabricatorNamedQuery())
|
||||
->setUserPHID($this->requireViewer()->getPHID())
|
||||
->setUserPHID(PhabricatorNamedQuery::SCOPE_GLOBAL)
|
||||
->setEngineClassName(get_class($this))
|
||||
->setQueryName($name)
|
||||
->setQueryKey($key)
|
||||
|
|
|
@ -465,7 +465,7 @@ abstract class PhabricatorProfileMenuEngine extends Phobject {
|
|||
$default = null;
|
||||
$first = null;
|
||||
foreach ($items as $item) {
|
||||
if (!$item->canMakeDefault()) {
|
||||
if (!$item->canMakeDefault() || $item->isDisabled()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorNamedQueryConfigQuery
|
||||
extends PhabricatorCursorPagedPolicyAwareQuery {
|
||||
|
||||
private $ids;
|
||||
private $engineClassNames;
|
||||
private $scopePHIDs;
|
||||
|
||||
public function withIDs(array $ids) {
|
||||
$this->ids = $ids;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withScopePHIDs(array $scope_phids) {
|
||||
$this->scopePHIDs = $scope_phids;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withEngineClassNames(array $engine_class_names) {
|
||||
$this->engineClassNames = $engine_class_names;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function newResultObject() {
|
||||
return new PhabricatorNamedQueryConfig();
|
||||
}
|
||||
|
||||
protected function loadPage() {
|
||||
return $this->loadStandardPage($this->newResultObject());
|
||||
}
|
||||
|
||||
protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
|
||||
$where = parent::buildWhereClauseParts($conn);
|
||||
|
||||
if ($this->ids !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'id IN (%Ld)',
|
||||
$this->ids);
|
||||
}
|
||||
|
||||
if ($this->engineClassNames !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'engineClassName IN (%Ls)',
|
||||
$this->engineClassNames);
|
||||
}
|
||||
|
||||
if ($this->scopePHIDs !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'scopePHID IN (%Ls)',
|
||||
$this->scopePHIDs);
|
||||
}
|
||||
|
||||
return $where;
|
||||
}
|
||||
|
||||
public function getQueryApplicationClass() {
|
||||
return 'PhabricatorSearchApplication';
|
||||
}
|
||||
|
||||
}
|
|
@ -12,6 +12,8 @@ final class PhabricatorNamedQuery extends PhabricatorSearchDAO
|
|||
protected $isDisabled = 0;
|
||||
protected $sequence = 0;
|
||||
|
||||
const SCOPE_GLOBAL = 'scope.global';
|
||||
|
||||
protected function getConfiguration() {
|
||||
return array(
|
||||
self::CONFIG_COLUMN_SCHEMA => array(
|
||||
|
@ -31,8 +33,29 @@ final class PhabricatorNamedQuery extends PhabricatorSearchDAO
|
|||
) + parent::getConfiguration();
|
||||
}
|
||||
|
||||
public function getSortKey() {
|
||||
return sprintf('~%010d%010d', $this->sequence, $this->getID());
|
||||
public function isGlobal() {
|
||||
if ($this->getIsBuiltin()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($this->getUserPHID() === self::SCOPE_GLOBAL) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getNamedQuerySortVector() {
|
||||
if (!$this->isGlobal()) {
|
||||
$phase = 0;
|
||||
} else {
|
||||
$phase = 1;
|
||||
}
|
||||
|
||||
return id(new PhutilSortVector())
|
||||
->addInt($phase)
|
||||
->addInt($this->sequence)
|
||||
->addInt($this->getID());
|
||||
}
|
||||
|
||||
/* -( PhabricatorPolicyInterface )----------------------------------------- */
|
||||
|
@ -41,6 +64,7 @@ final class PhabricatorNamedQuery extends PhabricatorSearchDAO
|
|||
public function getCapabilities() {
|
||||
return array(
|
||||
PhabricatorPolicyCapability::CAN_VIEW,
|
||||
PhabricatorPolicyCapability::CAN_EDIT,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -49,9 +73,19 @@ final class PhabricatorNamedQuery extends PhabricatorSearchDAO
|
|||
}
|
||||
|
||||
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
|
||||
if ($viewer->getPHID() == $this->userPHID) {
|
||||
if ($viewer->getPHID() == $this->getUserPHID()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($this->isGlobal()) {
|
||||
switch ($capability) {
|
||||
case PhabricatorPolicyCapability::CAN_VIEW:
|
||||
return true;
|
||||
case PhabricatorPolicyCapability::CAN_EDIT:
|
||||
return $viewer->getIsAdmin();
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorNamedQueryConfig
|
||||
extends PhabricatorSearchDAO
|
||||
implements PhabricatorPolicyInterface {
|
||||
|
||||
protected $engineClassName;
|
||||
protected $scopePHID;
|
||||
protected $properties = array();
|
||||
|
||||
const SCOPE_GLOBAL = 'scope.global';
|
||||
|
||||
const PROPERTY_PINNED = 'pinned';
|
||||
|
||||
protected function getConfiguration() {
|
||||
return array(
|
||||
self::CONFIG_SERIALIZATION => array(
|
||||
'properties' => self::SERIALIZATION_JSON,
|
||||
),
|
||||
self::CONFIG_COLUMN_SCHEMA => array(
|
||||
'engineClassName' => 'text128',
|
||||
),
|
||||
self::CONFIG_KEY_SCHEMA => array(
|
||||
'key_scope' => array(
|
||||
'columns' => array('engineClassName', 'scopePHID'),
|
||||
'unique' => true,
|
||||
),
|
||||
),
|
||||
) + parent::getConfiguration();
|
||||
}
|
||||
|
||||
public static function initializeNewQueryConfig() {
|
||||
return new self();
|
||||
}
|
||||
|
||||
public function isGlobal() {
|
||||
return ($this->getScopePHID() == self::SCOPE_GLOBAL);
|
||||
}
|
||||
|
||||
public function getConfigProperty($key, $default = null) {
|
||||
return idx($this->properties, $key, $default);
|
||||
}
|
||||
|
||||
public function setConfigProperty($key, $value) {
|
||||
$this->properties[$key] = $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getStrengthSortVector() {
|
||||
// Apply personal preferences before global preferences.
|
||||
if (!$this->isGlobal()) {
|
||||
$phase = 0;
|
||||
} else {
|
||||
$phase = 1;
|
||||
}
|
||||
|
||||
return id(new PhutilSortVector())
|
||||
->addInt($phase)
|
||||
->addInt($this->getID());
|
||||
}
|
||||
|
||||
|
||||
/* -( PhabricatorPolicyInterface )----------------------------------------- */
|
||||
|
||||
|
||||
public function getCapabilities() {
|
||||
return array(
|
||||
PhabricatorPolicyCapability::CAN_VIEW,
|
||||
);
|
||||
}
|
||||
|
||||
public function getPolicy($capability) {
|
||||
return PhabricatorPolicies::POLICY_NOONE;
|
||||
}
|
||||
|
||||
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
|
||||
if ($this->isGlobal()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($viewer->getPHID() == $this->getScopePHID()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function describeAutomaticCapability($capability) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorDesktopNotificationsSettingsPanel
|
||||
final class PhabricatorNotificationsSettingsPanel
|
||||
extends PhabricatorSettingsPanel {
|
||||
|
||||
public function isEnabled() {
|
||||
|
@ -14,11 +14,11 @@ final class PhabricatorDesktopNotificationsSettingsPanel
|
|||
}
|
||||
|
||||
public function getPanelKey() {
|
||||
return 'desktopnotifications';
|
||||
return 'notifications';
|
||||
}
|
||||
|
||||
public function getPanelName() {
|
||||
return pht('Desktop Notifications');
|
||||
return pht('Notifications');
|
||||
}
|
||||
|
||||
public function getPanelGroupKey() {
|
||||
|
@ -29,7 +29,7 @@ final class PhabricatorDesktopNotificationsSettingsPanel
|
|||
$viewer = $this->getViewer();
|
||||
$preferences = $this->getPreferences();
|
||||
|
||||
$notifications_key = PhabricatorDesktopNotificationsSetting::SETTINGKEY;
|
||||
$notifications_key = PhabricatorNotificationsSetting::SETTINGKEY;
|
||||
$notifications_value = $preferences->getSettingValue($notifications_key);
|
||||
|
||||
if ($request->isFormPost()) {
|
||||
|
@ -43,7 +43,7 @@ final class PhabricatorDesktopNotificationsSettingsPanel
|
|||
->setURI($this->getPanelURI('?saved=true'));
|
||||
}
|
||||
|
||||
$title = pht('Desktop Notifications');
|
||||
$title = pht('Notifications');
|
||||
$control_id = celerity_generate_unique_node_id();
|
||||
$status_id = celerity_generate_unique_node_id();
|
||||
$browser_status_id = celerity_generate_unique_node_id();
|
||||
|
@ -97,19 +97,31 @@ final class PhabricatorDesktopNotificationsSettingsPanel
|
|||
'id' => $message_id,
|
||||
));
|
||||
|
||||
$saved_box = null;
|
||||
if ($request->getBool('saved')) {
|
||||
$saved_box = id(new PHUIInfoView())
|
||||
->setSeverity(PHUIInfoView::SEVERITY_NOTICE)
|
||||
->appendChild(pht('Changes saved.'));
|
||||
}
|
||||
|
||||
$status_box = id(new PHUIInfoView())
|
||||
->setSeverity(PHUIInfoView::SEVERITY_NOTICE)
|
||||
->setID($status_id)
|
||||
->setIsHidden(true)
|
||||
->appendChild($message_container);
|
||||
|
||||
$status_box = id(new PHUIBoxView())
|
||||
->addClass('mll mlr')
|
||||
->appendChild($status_box);
|
||||
|
||||
$control_config = array(
|
||||
'controlID' => $control_id,
|
||||
'statusID' => $status_id,
|
||||
'messageID' => $message_id,
|
||||
'browserStatusID' => $browser_status_id,
|
||||
'defaultMode' => 0,
|
||||
'desktopMode' => 1,
|
||||
'desktop' => 1,
|
||||
'desktopOnly' => 2,
|
||||
'cancelAsk' => $cancel_ask,
|
||||
'grantedAsk' => $accept_ask,
|
||||
'deniedAsk' => $reject_ask,
|
||||
|
@ -127,16 +139,12 @@ final class PhabricatorDesktopNotificationsSettingsPanel
|
|||
->setControlID($control_id)
|
||||
->setName($notifications_key)
|
||||
->setValue($notifications_value)
|
||||
->setOptions(
|
||||
array(
|
||||
1 => pht('Send Desktop Notifications Too'),
|
||||
0 => pht('Send Application Notifications Only'),
|
||||
))
|
||||
->setOptions(PhabricatorNotificationsSetting::getOptionsMap())
|
||||
->setCaption(
|
||||
pht(
|
||||
'Should Phabricator send desktop notifications? These are sent '.
|
||||
'in addition to the notifications within the Phabricator '.
|
||||
'application.'))
|
||||
'Phabricator can send real-time notifications to your web browser '.
|
||||
'or to your desktop. Select where you\'d want to receive these '.
|
||||
'real-time updates.'))
|
||||
->initBehavior(
|
||||
'desktop-notifications-control',
|
||||
$control_config))
|
||||
|
@ -154,12 +162,14 @@ final class PhabricatorDesktopNotificationsSettingsPanel
|
|||
$form_box = id(new PHUIObjectBoxView())
|
||||
->setHeader(
|
||||
id(new PHUIHeaderView())
|
||||
->setHeader(pht('Desktop Notifications'))
|
||||
->setHeader(pht('Notifications'))
|
||||
->addActionLink($test_button))
|
||||
->setForm($form)
|
||||
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
||||
->setInfoView($status_box)
|
||||
->setFormSaved($request->getBool('saved'));
|
||||
->appendChild(array(
|
||||
$saved_box,
|
||||
$status_box,
|
||||
$form,
|
||||
));
|
||||
|
||||
$browser_status_box = id(new PHUIInfoView())
|
||||
->setID($browser_status_id)
|
|
@ -1,12 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorDesktopNotificationsSetting
|
||||
extends PhabricatorInternalSetting {
|
||||
|
||||
const SETTINGKEY = 'desktop-notifications';
|
||||
|
||||
public function getSettingName() {
|
||||
return pht('Desktop Notifications');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorNotificationsSetting
|
||||
extends PhabricatorInternalSetting {
|
||||
|
||||
const SETTINGKEY = 'desktop-notifications';
|
||||
|
||||
const WEB_ONLY = 0;
|
||||
const WEB_AND_DESKTOP = 1;
|
||||
const DESKTOP_ONLY = 2;
|
||||
const NONE = 3;
|
||||
|
||||
public function getSettingName() {
|
||||
return pht('Notifications');
|
||||
}
|
||||
|
||||
public static function getOptionsMap() {
|
||||
return array(
|
||||
self::WEB_ONLY => pht('Web Only'),
|
||||
self::WEB_AND_DESKTOP => pht('Web and Desktop'),
|
||||
self::DESKTOP_ONLY => pht('Desktop Only'),
|
||||
self::NONE => pht('No Notifications'),
|
||||
);
|
||||
}
|
||||
|
||||
public static function desktopReady($option) {
|
||||
switch ($option) {
|
||||
case self::WEB_AND_DESKTOP:
|
||||
case self::DESKTOP_ONLY:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function webReady($option) {
|
||||
switch ($option) {
|
||||
case self::WEB_AND_DESKTOP:
|
||||
case self::WEB_ONLY:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,216 @@
|
|||
<?php
|
||||
|
||||
final class TransactionSearchConduitAPIMethod
|
||||
extends ConduitAPIMethod {
|
||||
|
||||
public function getAPIMethodName() {
|
||||
return 'transaction.search';
|
||||
}
|
||||
|
||||
public function getMethodDescription() {
|
||||
return pht('Read transactions for an object.');
|
||||
}
|
||||
|
||||
public function getMethodStatus() {
|
||||
return self::METHOD_STATUS_UNSTABLE;
|
||||
}
|
||||
|
||||
public function getMethodStatusDescription() {
|
||||
return pht('This method is new and experimental.');
|
||||
}
|
||||
|
||||
protected function defineParamTypes() {
|
||||
return array(
|
||||
'objectIdentifier' => 'phid|string',
|
||||
) + $this->getPagerParamTypes();
|
||||
}
|
||||
|
||||
protected function defineReturnType() {
|
||||
return 'list<dict>';
|
||||
}
|
||||
|
||||
protected function defineErrorTypes() {
|
||||
return array();
|
||||
}
|
||||
|
||||
protected function execute(ConduitAPIRequest $request) {
|
||||
$viewer = $request->getUser();
|
||||
$pager = $this->newPager($request);
|
||||
|
||||
$object_name = $request->getValue('objectIdentifier', null);
|
||||
if (!strlen($object_name)) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'When calling "transaction.search", you must provide an object to '.
|
||||
'retrieve transactions for.'));
|
||||
}
|
||||
|
||||
$object = id(new PhabricatorObjectQuery())
|
||||
->setViewer($viewer)
|
||||
->withNames(array($object_name))
|
||||
->executeOne();
|
||||
if (!$object) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'No object "%s" exists.',
|
||||
$object_name));
|
||||
}
|
||||
|
||||
if (!($object instanceof PhabricatorApplicationTransactionInterface)) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Object "%s" does not implement "%s", so transactions can not '.
|
||||
'be loaded for it.'));
|
||||
}
|
||||
|
||||
$xaction_query = PhabricatorApplicationTransactionQuery::newQueryForObject(
|
||||
$object);
|
||||
|
||||
$xactions = $xaction_query
|
||||
->withObjectPHIDs(array($object->getPHID()))
|
||||
->setViewer($viewer)
|
||||
->executeWithCursorPager($pager);
|
||||
|
||||
if ($xactions) {
|
||||
$template = head($xactions)->getApplicationTransactionCommentObject();
|
||||
|
||||
$query = new PhabricatorApplicationTransactionTemplatedCommentQuery();
|
||||
|
||||
$comment_map = $query
|
||||
->setViewer($viewer)
|
||||
->setTemplate($template)
|
||||
->withTransactionPHIDs(mpull($xactions, 'getPHID'))
|
||||
->execute();
|
||||
|
||||
$comment_map = msort($comment_map, 'getCommentVersion');
|
||||
$comment_map = array_reverse($comment_map);
|
||||
$comment_map = mgroup($comment_map, 'getTransactionPHID');
|
||||
} else {
|
||||
$comment_map = array();
|
||||
}
|
||||
|
||||
$modular_classes = array();
|
||||
$modular_objects = array();
|
||||
$modular_xactions = array();
|
||||
foreach ($xactions as $xaction) {
|
||||
if (!$xaction instanceof PhabricatorModularTransaction) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO: Hack things so certain transactions which don't have a modular
|
||||
// type yet can use a pseudotype until they modularize. Some day, we'll
|
||||
// modularize everything and remove this.
|
||||
switch ($xaction->getTransactionType()) {
|
||||
case DifferentialTransaction::TYPE_INLINE:
|
||||
$modular_template = new DifferentialRevisionInlineTransaction();
|
||||
break;
|
||||
default:
|
||||
$modular_template = $xaction->getModularType();
|
||||
break;
|
||||
}
|
||||
|
||||
$modular_class = get_class($modular_template);
|
||||
if (!isset($modular_objects[$modular_class])) {
|
||||
try {
|
||||
$modular_object = newv($modular_class, array());
|
||||
$modular_objects[$modular_class] = $modular_object;
|
||||
} catch (Exception $ex) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$modular_classes[$xaction->getPHID()] = $modular_class;
|
||||
$modular_xactions[$modular_class][] = $xaction;
|
||||
}
|
||||
|
||||
$modular_data_map = array();
|
||||
foreach ($modular_objects as $class => $modular_type) {
|
||||
$modular_data_map[$class] = $modular_type
|
||||
->setViewer($viewer)
|
||||
->loadTransactionTypeConduitData($modular_xactions[$class]);
|
||||
}
|
||||
|
||||
$data = array();
|
||||
foreach ($xactions as $xaction) {
|
||||
$comments = idx($comment_map, $xaction->getPHID());
|
||||
|
||||
$comment_data = array();
|
||||
if ($comments) {
|
||||
$removed = head($comments)->getIsDeleted();
|
||||
|
||||
foreach ($comments as $comment) {
|
||||
if ($removed) {
|
||||
// If the most recent version of the comment has been removed,
|
||||
// don't show the history. This is for consistency with the web
|
||||
// UI, which also prevents users from retrieving the content of
|
||||
// removed comments.
|
||||
$content = array(
|
||||
'raw' => '',
|
||||
);
|
||||
} else {
|
||||
$content = array(
|
||||
'raw' => (string)$comment->getContent(),
|
||||
);
|
||||
}
|
||||
|
||||
$comment_data[] = array(
|
||||
'id' => (int)$comment->getID(),
|
||||
'phid' => (string)$comment->getPHID(),
|
||||
'version' => (int)$comment->getCommentVersion(),
|
||||
'authorPHID' => (string)$comment->getAuthorPHID(),
|
||||
'dateCreated' => (int)$comment->getDateCreated(),
|
||||
'dateModified' => (int)$comment->getDateModified(),
|
||||
'removed' => (bool)$comment->getIsDeleted(),
|
||||
'content' => $content,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$fields = array();
|
||||
$type = null;
|
||||
|
||||
if (isset($modular_classes[$xaction->getPHID()])) {
|
||||
$modular_class = $modular_classes[$xaction->getPHID()];
|
||||
$modular_object = $modular_objects[$modular_class];
|
||||
$modular_data = $modular_data_map[$modular_class];
|
||||
|
||||
$type = $modular_object->getTransactionTypeForConduit($xaction);
|
||||
$fields = $modular_object->getFieldValuesForConduit(
|
||||
$xaction,
|
||||
$modular_data);
|
||||
}
|
||||
|
||||
if (!$fields) {
|
||||
$fields = (object)$fields;
|
||||
}
|
||||
|
||||
// If we haven't found a modular type, fallback for some simple core
|
||||
// types. Ideally, we'll modularize everything some day.
|
||||
if ($type === null) {
|
||||
switch ($xaction->getTransactionType()) {
|
||||
case PhabricatorTransactions::TYPE_COMMENT:
|
||||
$type = 'comment';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$data[] = array(
|
||||
'id' => (int)$xaction->getID(),
|
||||
'phid' => (string)$xaction->getPHID(),
|
||||
'type' => $type,
|
||||
'authorPHID' => (string)$xaction->getAuthorPHID(),
|
||||
'objectPHID' => (string)$xaction->getObjectPHID(),
|
||||
'dateCreated' => (int)$xaction->getDateCreated(),
|
||||
'dateModified' => (int)$xaction->getDateModified(),
|
||||
'comments' => $comment_data,
|
||||
'fields' => $fields,
|
||||
);
|
||||
}
|
||||
|
||||
$results = array(
|
||||
'data' => $data,
|
||||
);
|
||||
|
||||
return $this->addPagerResults($results, $pager);
|
||||
}
|
||||
}
|
|
@ -486,8 +486,6 @@ abstract class PhabricatorApplicationTransactionEditor
|
|||
switch ($xaction->getTransactionType()) {
|
||||
case PhabricatorTransactions::TYPE_CREATE:
|
||||
return true;
|
||||
case PhabricatorTransactions::TYPE_COMMENT:
|
||||
return $xaction->hasComment();
|
||||
case PhabricatorTransactions::TYPE_CUSTOMFIELD:
|
||||
$field = $this->getCustomFieldForTransaction($object, $xaction);
|
||||
return $field->getApplicationTransactionHasEffect($xaction);
|
||||
|
@ -534,6 +532,10 @@ abstract class PhabricatorApplicationTransactionEditor
|
|||
$xaction->getNewValue());
|
||||
}
|
||||
|
||||
if ($xaction->hasComment()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return ($xaction->getOldValue() !== $xaction->getNewValue());
|
||||
}
|
||||
|
||||
|
|
|
@ -332,4 +332,16 @@ abstract class PhabricatorModularTransactionType
|
|||
return $this->getStorage()->getMetadataValue($key, $default);
|
||||
}
|
||||
|
||||
public function loadTransactionTypeConduitData(array $xactions) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getTransactionTypeForConduit($xaction) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getFieldValuesForConduit($xaction, $data) {
|
||||
return array();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -58,10 +58,12 @@ final class PHUIButtonExample extends PhabricatorUIExample {
|
|||
array(
|
||||
'text' => pht('Comment'),
|
||||
'icon' => 'fa-comment',
|
||||
'dropdown' => true,
|
||||
),
|
||||
array(
|
||||
'text' => pht('Give Token'),
|
||||
'icon' => 'fa-trophy',
|
||||
'dropdown' => true,
|
||||
),
|
||||
array(
|
||||
'text' => pht('Reverse Time'),
|
||||
|
@ -73,9 +75,11 @@ final class PHUIButtonExample extends PhabricatorUIExample {
|
|||
),
|
||||
array(
|
||||
'icon' => 'fa-rocket',
|
||||
'dropdown' => true,
|
||||
),
|
||||
array(
|
||||
'icon' => 'fa-clipboard',
|
||||
'dropdown' => true,
|
||||
),
|
||||
array(
|
||||
'icon' => 'fa-upload',
|
||||
|
@ -95,7 +99,8 @@ final class PHUIButtonExample extends PhabricatorUIExample {
|
|||
->setColor(PHUIButtonView::GREY)
|
||||
->setIcon(idx($spec, 'icon'))
|
||||
->setText(idx($spec, 'text'))
|
||||
->addClass(PHUI::MARGIN_SMALL_RIGHT);
|
||||
->addClass(PHUI::MARGIN_SMALL_RIGHT)
|
||||
->setDropdown(idx($spec, 'dropdown'));
|
||||
|
||||
$copy = idx($spec, 'copy');
|
||||
if ($copy !== null) {
|
||||
|
|
|
@ -153,6 +153,12 @@ to a Project or to a Home menu, that Dashboard will be presented in the
|
|||
context of that menu. This allows customization of different pages of content
|
||||
without having the user leave Home or the Project.
|
||||
|
||||
To use a Dashboard to replace the default Home menu, install it as a Global
|
||||
Menu Item and move it to the topmost item. By default, the first Dashboard
|
||||
the menu renders will be selected as the default. Users that modify their
|
||||
personal Home menu, will have their topmost Dashboard be their default,
|
||||
overriding the Global settings.
|
||||
|
||||
|
||||
Writing New Item Types
|
||||
======================
|
||||
|
|
|
@ -166,7 +166,7 @@
|
|||
border: none;
|
||||
background-color: {$page.content};
|
||||
height: 28px;
|
||||
padding: 3px 28px 3px 52px;
|
||||
padding: 3px 28px 3px 48px;
|
||||
float: left;
|
||||
width: 280px;
|
||||
}
|
||||
|
@ -212,7 +212,7 @@
|
|||
position: absolute;
|
||||
right: auto;
|
||||
left: 12px;
|
||||
width: 46px;
|
||||
width: 40px;
|
||||
background: {$greybackground};
|
||||
z-index: 1;
|
||||
}
|
||||
|
@ -252,7 +252,7 @@ a.phabricator-core-user-menu .caret:before {
|
|||
|
||||
.phabricator-main-menu-search-dropdown .caret {
|
||||
position: absolute;
|
||||
right: 18px;
|
||||
right: 20px;
|
||||
top: 2px;
|
||||
border: none;
|
||||
margin-top: 1px;
|
||||
|
|
|
@ -7,24 +7,22 @@
|
|||
background: {$page.content};
|
||||
}
|
||||
|
||||
.diffusion-source tr.phabricator-source-highlight {
|
||||
background: {$sh-yellowbackground};
|
||||
.diffusion-source tr.phabricator-source-highlight th,
|
||||
.diffusion-source tr.phabricator-source-highlight td {
|
||||
background: {$gentle.highlight};
|
||||
}
|
||||
|
||||
.diffusion-source th {
|
||||
text-align: right;
|
||||
vertical-align: top;
|
||||
background: {$lightgreybackground};
|
||||
color: {$bluetext};
|
||||
color: {$darkbluetext};
|
||||
border-right: 1px solid {$thinblueborder};
|
||||
}
|
||||
|
||||
.diffusion-source td {
|
||||
vertical-align: top;
|
||||
white-space: pre-wrap;
|
||||
padding-top: 1px;
|
||||
padding-bottom: 1px;
|
||||
padding-left: 8px;
|
||||
padding: 3px 12px;
|
||||
width: 100%;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
@ -34,12 +32,18 @@
|
|||
}
|
||||
|
||||
.diffusion-blame-link,
|
||||
.diffusion-rev-link {
|
||||
.diffusion-rev-link,
|
||||
.diffusion-blame-date {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.diffusion-blame-link {
|
||||
min-width: 28px;
|
||||
.diffusion-blame-date,
|
||||
.diffusion-blame-link,
|
||||
.diffusion-blame-revision,
|
||||
.diffusion-rev-link {
|
||||
background: {$lightgreybackground};
|
||||
font: {$basefont};
|
||||
font-size: {$smallerfontsize};
|
||||
}
|
||||
|
||||
.diffusion-source th.diffusion-rev-link {
|
||||
|
@ -47,16 +51,23 @@
|
|||
min-width: 130px;
|
||||
}
|
||||
|
||||
.diffusion-blame-link a,
|
||||
.diffusion-rev-link a,
|
||||
.diffusion-line-link a {
|
||||
.diffusion-source a {
|
||||
color: {$darkbluetext};
|
||||
}
|
||||
|
||||
.diffusion-rev-link a,
|
||||
.diffusion-rev-link span {
|
||||
margin: 2px 8px 0;
|
||||
display: inline-block;
|
||||
.diffusion-rev-link a {
|
||||
max-width: 300px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
margin: 3px 8px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.diffusion-blame-date a,
|
||||
.diffusion-blame-revision a {
|
||||
float: right;
|
||||
margin: 3px 8px;
|
||||
}
|
||||
|
||||
.diffusion-rev-link span {
|
||||
|
@ -69,7 +80,19 @@
|
|||
.diffusion-line-link a {
|
||||
/* Give the user a larger click target. */
|
||||
display: block;
|
||||
padding: 2px 8px;
|
||||
padding: 4px 8px 3px;
|
||||
}
|
||||
|
||||
.diffusion-line-link a {
|
||||
color: {$lightgreytext};
|
||||
}
|
||||
|
||||
.diffusion-blame-link a .phui-icon-view {
|
||||
color: {$bluetext};
|
||||
}
|
||||
|
||||
.diffusion-blame-link a:hover .phui-icon-view {
|
||||
color: {$sky};
|
||||
}
|
||||
|
||||
.diffusion-line-link {
|
||||
|
|
|
@ -271,11 +271,17 @@ a.policy-control .phui-button-text {
|
|||
position: relative;
|
||||
}
|
||||
|
||||
.button.has-icon.dropdown .phui-icon-view {
|
||||
margin-right: 8px;
|
||||
margin-left: -2px;
|
||||
}
|
||||
|
||||
.button.has-text .phui-icon-view {
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
top: 7px;
|
||||
left: 12px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.button.icon-last .phui-icon-view {
|
||||
|
|
|
@ -112,12 +112,6 @@
|
|||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
.device-desktop li.phabricator-action-view-label:hover
|
||||
.phabricator-action-view-item {
|
||||
background-color: {$page.content};
|
||||
color: {$bluetext};
|
||||
}
|
||||
|
||||
.phabricator-action-view + .phabricator-action-view-label {
|
||||
padding-top: 8px;
|
||||
}
|
||||
|
|
|
@ -187,8 +187,8 @@ body .phui-header-shell.phui-bleed-header
|
|||
margin-right: 4px;
|
||||
}
|
||||
|
||||
.phui-header-subheader .phui-tag-view .phui-icon-view,
|
||||
.phui-header-subheader .policy-header-callout .phui-icon-view {
|
||||
.phui-header-subheader .phui-tag-view span.phui-icon-view,
|
||||
.phui-header-subheader .policy-header-callout span.phui-icon-view {
|
||||
display: inline-block;
|
||||
margin: -2px 4px -2px 0;
|
||||
font-size: 15px;
|
||||
|
|
|
@ -82,6 +82,7 @@ JX.behavior('aphlict-listen', function(config) {
|
|||
new JX.Notification()
|
||||
.setContent(JX.$H(response.content))
|
||||
.setDesktopReady(response.desktopReady)
|
||||
.setWebReady(response.webReady)
|
||||
.setKey(response.primaryObjectPHID)
|
||||
.setTitle(response.title)
|
||||
.setBody(response.body)
|
||||
|
|
|
@ -84,7 +84,7 @@ JX.behavior('desktop-notifications-control', function(config, statics) {
|
|||
return;
|
||||
}
|
||||
var value = e.getTarget().value;
|
||||
if (value == config.desktopMode) {
|
||||
if ((value == config.desktop) || (value == config.desktopOnly)) {
|
||||
window.Notification.requestPermission(
|
||||
function (permission) {
|
||||
updateFormStatus(permission);
|
||||
|
|
|
@ -17,6 +17,13 @@ JX.behavior('phabricator-show-older-transactions', function(config) {
|
|||
if (!hash) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the hash isn't purely numeric, ignore it. Comments always have
|
||||
// numeric hashes. See PHI43 and T12970.
|
||||
if (!hash.match(/^\d+$/)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var id = 'anchor-'+hash;
|
||||
try {
|
||||
JX.$(id);
|
||||
|
|
|
@ -27,6 +27,7 @@ JX.install('Notification', {
|
|||
_hideTimer : null,
|
||||
_duration : 12000,
|
||||
_desktopReady : false,
|
||||
_webReady : false,
|
||||
_key : null,
|
||||
_title : null,
|
||||
_body : null,
|
||||
|
@ -35,6 +36,12 @@ JX.install('Notification', {
|
|||
|
||||
show : function() {
|
||||
var self = JX.Notification;
|
||||
|
||||
// This person doesn't like any real-time notification
|
||||
if (!this._desktopReady && !this._webReady) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this._visible) {
|
||||
this._visible = true;
|
||||
|
||||
|
@ -92,6 +99,11 @@ JX.install('Notification', {
|
|||
return this;
|
||||
},
|
||||
|
||||
setWebReady : function(ready) {
|
||||
this._webReady = ready;
|
||||
return this;
|
||||
},
|
||||
|
||||
setTitle : function(title) {
|
||||
this._title = title;
|
||||
return this;
|
||||
|
|
Loading…
Reference in a new issue