1
0
Fork 0
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:
epriestley 2017-08-25 11:27:45 -07:00
commit 77c11e7ae9
46 changed files with 1276 additions and 367 deletions

View file

@ -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',

View 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};

View 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();
}

View file

@ -0,0 +1,2 @@
ALTER TABLE {$NAMESPACE}_phame.phame_post
DROP COLUMN views;

View file

@ -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',

View file

@ -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) {

View file

@ -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(

View file

@ -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(),
);
}
}

View file

@ -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(),
);
}
}

View file

@ -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(),
);
}
}

View file

@ -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());

View file

@ -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;
}

View file

@ -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']) {

View file

@ -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,

View file

@ -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'],

View file

@ -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();

View file

@ -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;
}

View file

@ -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?',

View file

@ -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);
}
}

View file

@ -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',

View file

@ -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();

View file

@ -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);
}
}

View file

@ -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;

View file

@ -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'))

View file

@ -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)

View file

@ -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;
}

View file

@ -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';
}
}

View file

@ -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;
}

View file

@ -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;
}
}

View file

@ -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)

View file

@ -1,12 +0,0 @@
<?php
final class PhabricatorDesktopNotificationsSetting
extends PhabricatorInternalSetting {
const SETTINGKEY = 'desktop-notifications';
public function getSettingName() {
return pht('Desktop Notifications');
}
}

View file

@ -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;
}
}

View file

@ -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);
}
}

View file

@ -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());
}

View file

@ -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();
}
}

View file

@ -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) {

View file

@ -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
======================

View file

@ -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;

View file

@ -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 {

View file

@ -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 {

View file

@ -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;
}

View file

@ -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;

View file

@ -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)

View file

@ -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);

View file

@ -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);

View file

@ -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;