diff --git a/resources/builtin/projects/fa-android.png b/resources/builtin/projects/fa-android.png new file mode 100644 index 0000000000..db56162683 Binary files /dev/null and b/resources/builtin/projects/fa-android.png differ diff --git a/resources/builtin/projects/fa-apple.png b/resources/builtin/projects/fa-apple.png new file mode 100644 index 0000000000..7e289818d1 Binary files /dev/null and b/resources/builtin/projects/fa-apple.png differ diff --git a/resources/builtin/projects/fa-beer.png b/resources/builtin/projects/fa-beer.png new file mode 100644 index 0000000000..ff5fd0646f Binary files /dev/null and b/resources/builtin/projects/fa-beer.png differ diff --git a/resources/builtin/projects/fa-bomb.png b/resources/builtin/projects/fa-bomb.png new file mode 100644 index 0000000000..bfeacfa84c Binary files /dev/null and b/resources/builtin/projects/fa-bomb.png differ diff --git a/resources/builtin/projects/fa-book.png b/resources/builtin/projects/fa-book.png new file mode 100644 index 0000000000..f6bda5d61c Binary files /dev/null and b/resources/builtin/projects/fa-book.png differ diff --git a/resources/builtin/projects/fa-briefcase.png b/resources/builtin/projects/fa-briefcase.png new file mode 100644 index 0000000000..afa70e2a3a Binary files /dev/null and b/resources/builtin/projects/fa-briefcase.png differ diff --git a/resources/builtin/projects/fa-bug.png b/resources/builtin/projects/fa-bug.png new file mode 100644 index 0000000000..83c538f885 Binary files /dev/null and b/resources/builtin/projects/fa-bug.png differ diff --git a/resources/builtin/projects/fa-building.png b/resources/builtin/projects/fa-building.png new file mode 100644 index 0000000000..d033366cf7 Binary files /dev/null and b/resources/builtin/projects/fa-building.png differ diff --git a/resources/builtin/projects/fa-calendar.png b/resources/builtin/projects/fa-calendar.png new file mode 100644 index 0000000000..80cfc3e11b Binary files /dev/null and b/resources/builtin/projects/fa-calendar.png differ diff --git a/resources/builtin/projects/fa-camera-retro.png b/resources/builtin/projects/fa-camera-retro.png new file mode 100644 index 0000000000..c1ac04d27b Binary files /dev/null and b/resources/builtin/projects/fa-camera-retro.png differ diff --git a/resources/builtin/projects/fa-chrome.png b/resources/builtin/projects/fa-chrome.png new file mode 100644 index 0000000000..177c2fe4f3 Binary files /dev/null and b/resources/builtin/projects/fa-chrome.png differ diff --git a/resources/builtin/projects/fa-cloud.png b/resources/builtin/projects/fa-cloud.png new file mode 100644 index 0000000000..ae1b855f94 Binary files /dev/null and b/resources/builtin/projects/fa-cloud.png differ diff --git a/resources/builtin/projects/fa-coffee.png b/resources/builtin/projects/fa-coffee.png new file mode 100644 index 0000000000..8d0850f0ee Binary files /dev/null and b/resources/builtin/projects/fa-coffee.png differ diff --git a/resources/builtin/projects/fa-comments.png b/resources/builtin/projects/fa-comments.png new file mode 100644 index 0000000000..927fb91bb2 Binary files /dev/null and b/resources/builtin/projects/fa-comments.png differ diff --git a/resources/builtin/projects/fa-credit-card.png b/resources/builtin/projects/fa-credit-card.png new file mode 100644 index 0000000000..c159d2b673 Binary files /dev/null and b/resources/builtin/projects/fa-credit-card.png differ diff --git a/resources/builtin/projects/fa-database.png b/resources/builtin/projects/fa-database.png new file mode 100644 index 0000000000..bafcd1e338 Binary files /dev/null and b/resources/builtin/projects/fa-database.png differ diff --git a/resources/builtin/projects/fa-desktop.png b/resources/builtin/projects/fa-desktop.png new file mode 100644 index 0000000000..f463db8e1b Binary files /dev/null and b/resources/builtin/projects/fa-desktop.png differ diff --git a/resources/builtin/projects/fa-diamond.png b/resources/builtin/projects/fa-diamond.png new file mode 100644 index 0000000000..34a68c3284 Binary files /dev/null and b/resources/builtin/projects/fa-diamond.png differ diff --git a/resources/builtin/projects/fa-empire.png b/resources/builtin/projects/fa-empire.png new file mode 100644 index 0000000000..2d9dc3a8df Binary files /dev/null and b/resources/builtin/projects/fa-empire.png differ diff --git a/resources/builtin/projects/fa-envelope.png b/resources/builtin/projects/fa-envelope.png new file mode 100644 index 0000000000..934f1587bb Binary files /dev/null and b/resources/builtin/projects/fa-envelope.png differ diff --git a/resources/builtin/projects/fa-facebook.png b/resources/builtin/projects/fa-facebook.png new file mode 100644 index 0000000000..3d5a5f1f9a Binary files /dev/null and b/resources/builtin/projects/fa-facebook.png differ diff --git a/resources/builtin/projects/fa-fax.png b/resources/builtin/projects/fa-fax.png new file mode 100644 index 0000000000..af00c31269 Binary files /dev/null and b/resources/builtin/projects/fa-fax.png differ diff --git a/resources/builtin/projects/fa-film.png b/resources/builtin/projects/fa-film.png new file mode 100644 index 0000000000..2c30ffe477 Binary files /dev/null and b/resources/builtin/projects/fa-film.png differ diff --git a/resources/builtin/projects/fa-firefox.png b/resources/builtin/projects/fa-firefox.png new file mode 100644 index 0000000000..25fd9fc739 Binary files /dev/null and b/resources/builtin/projects/fa-firefox.png differ diff --git a/resources/builtin/projects/fa-flag-checkered.png b/resources/builtin/projects/fa-flag-checkered.png new file mode 100644 index 0000000000..e8e2519b4a Binary files /dev/null and b/resources/builtin/projects/fa-flag-checkered.png differ diff --git a/resources/builtin/projects/fa-flask.png b/resources/builtin/projects/fa-flask.png new file mode 100644 index 0000000000..ce978ae7d3 Binary files /dev/null and b/resources/builtin/projects/fa-flask.png differ diff --git a/resources/builtin/projects/fa-folder.png b/resources/builtin/projects/fa-folder.png new file mode 100644 index 0000000000..f6003fcd91 Binary files /dev/null and b/resources/builtin/projects/fa-folder.png differ diff --git a/resources/builtin/projects/fa-gamepad.png b/resources/builtin/projects/fa-gamepad.png new file mode 100644 index 0000000000..db3e7df75e Binary files /dev/null and b/resources/builtin/projects/fa-gamepad.png differ diff --git a/resources/builtin/projects/fa-gears.png b/resources/builtin/projects/fa-gears.png new file mode 100644 index 0000000000..8f60e32f84 Binary files /dev/null and b/resources/builtin/projects/fa-gears.png differ diff --git a/resources/builtin/projects/fa-google.png b/resources/builtin/projects/fa-google.png new file mode 100644 index 0000000000..cd1ad99b1b Binary files /dev/null and b/resources/builtin/projects/fa-google.png differ diff --git a/resources/builtin/projects/fa-hand-peace-o.png b/resources/builtin/projects/fa-hand-peace-o.png new file mode 100644 index 0000000000..20a9181f5c Binary files /dev/null and b/resources/builtin/projects/fa-hand-peace-o.png differ diff --git a/resources/builtin/projects/fa-hashtag.png b/resources/builtin/projects/fa-hashtag.png new file mode 100644 index 0000000000..3324b19a05 Binary files /dev/null and b/resources/builtin/projects/fa-hashtag.png differ diff --git a/resources/builtin/projects/fa-heart.png b/resources/builtin/projects/fa-heart.png new file mode 100644 index 0000000000..35733cacca Binary files /dev/null and b/resources/builtin/projects/fa-heart.png differ diff --git a/resources/builtin/projects/fa-internet-explorer.png b/resources/builtin/projects/fa-internet-explorer.png new file mode 100644 index 0000000000..34d30aabd9 Binary files /dev/null and b/resources/builtin/projects/fa-internet-explorer.png differ diff --git a/resources/builtin/projects/fa-key.png b/resources/builtin/projects/fa-key.png new file mode 100644 index 0000000000..8b7f810fe5 Binary files /dev/null and b/resources/builtin/projects/fa-key.png differ diff --git a/resources/builtin/projects/fa-legal.png b/resources/builtin/projects/fa-legal.png new file mode 100644 index 0000000000..52d217f6ba Binary files /dev/null and b/resources/builtin/projects/fa-legal.png differ diff --git a/resources/builtin/projects/fa-linux.png b/resources/builtin/projects/fa-linux.png new file mode 100644 index 0000000000..e0defe6671 Binary files /dev/null and b/resources/builtin/projects/fa-linux.png differ diff --git a/resources/builtin/projects/fa-lock.png b/resources/builtin/projects/fa-lock.png new file mode 100644 index 0000000000..4c7f552c65 Binary files /dev/null and b/resources/builtin/projects/fa-lock.png differ diff --git a/resources/builtin/projects/fa-microphone.png b/resources/builtin/projects/fa-microphone.png new file mode 100644 index 0000000000..d279fe6934 Binary files /dev/null and b/resources/builtin/projects/fa-microphone.png differ diff --git a/resources/builtin/projects/fa-mobile.png b/resources/builtin/projects/fa-mobile.png new file mode 100644 index 0000000000..3147473cb7 Binary files /dev/null and b/resources/builtin/projects/fa-mobile.png differ diff --git a/resources/builtin/projects/fa-money.png b/resources/builtin/projects/fa-money.png new file mode 100644 index 0000000000..e0823759e2 Binary files /dev/null and b/resources/builtin/projects/fa-money.png differ diff --git a/resources/builtin/projects/fa-phone.png b/resources/builtin/projects/fa-phone.png new file mode 100644 index 0000000000..ad5f77913f Binary files /dev/null and b/resources/builtin/projects/fa-phone.png differ diff --git a/resources/builtin/projects/fa-pie-chart.png b/resources/builtin/projects/fa-pie-chart.png new file mode 100644 index 0000000000..23fefc60c3 Binary files /dev/null and b/resources/builtin/projects/fa-pie-chart.png differ diff --git a/resources/builtin/projects/fa-rebel.png b/resources/builtin/projects/fa-rebel.png new file mode 100644 index 0000000000..1ada36553b Binary files /dev/null and b/resources/builtin/projects/fa-rebel.png differ diff --git a/resources/builtin/projects/fa-reddit-alien.png b/resources/builtin/projects/fa-reddit-alien.png new file mode 100644 index 0000000000..897eca4f39 Binary files /dev/null and b/resources/builtin/projects/fa-reddit-alien.png differ diff --git a/resources/builtin/projects/fa-safari.png b/resources/builtin/projects/fa-safari.png new file mode 100644 index 0000000000..fc056a7388 Binary files /dev/null and b/resources/builtin/projects/fa-safari.png differ diff --git a/resources/builtin/projects/fa-search.png b/resources/builtin/projects/fa-search.png new file mode 100644 index 0000000000..e4135af53a Binary files /dev/null and b/resources/builtin/projects/fa-search.png differ diff --git a/resources/builtin/projects/fa-server.png b/resources/builtin/projects/fa-server.png new file mode 100644 index 0000000000..3369e094b7 Binary files /dev/null and b/resources/builtin/projects/fa-server.png differ diff --git a/resources/builtin/projects/fa-shopping-cart.png b/resources/builtin/projects/fa-shopping-cart.png new file mode 100644 index 0000000000..5a623e9b62 Binary files /dev/null and b/resources/builtin/projects/fa-shopping-cart.png differ diff --git a/resources/builtin/projects/fa-sitemap.png b/resources/builtin/projects/fa-sitemap.png new file mode 100644 index 0000000000..81cbe5406d Binary files /dev/null and b/resources/builtin/projects/fa-sitemap.png differ diff --git a/resources/builtin/projects/fa-star.png b/resources/builtin/projects/fa-star.png new file mode 100644 index 0000000000..02b66e7ef2 Binary files /dev/null and b/resources/builtin/projects/fa-star.png differ diff --git a/resources/builtin/projects/fa-tablet.png b/resources/builtin/projects/fa-tablet.png new file mode 100644 index 0000000000..263e50d733 Binary files /dev/null and b/resources/builtin/projects/fa-tablet.png differ diff --git a/resources/builtin/projects/fa-tag.png b/resources/builtin/projects/fa-tag.png new file mode 100644 index 0000000000..558fbc40fb Binary files /dev/null and b/resources/builtin/projects/fa-tag.png differ diff --git a/resources/builtin/projects/fa-tags.png b/resources/builtin/projects/fa-tags.png new file mode 100644 index 0000000000..a491bdefbe Binary files /dev/null and b/resources/builtin/projects/fa-tags.png differ diff --git a/resources/builtin/projects/fa-trash-o.png b/resources/builtin/projects/fa-trash-o.png new file mode 100644 index 0000000000..03c0f0362a Binary files /dev/null and b/resources/builtin/projects/fa-trash-o.png differ diff --git a/resources/builtin/projects/fa-truck.png b/resources/builtin/projects/fa-truck.png new file mode 100644 index 0000000000..bb67c3157a Binary files /dev/null and b/resources/builtin/projects/fa-truck.png differ diff --git a/resources/builtin/projects/fa-twitter.png b/resources/builtin/projects/fa-twitter.png new file mode 100644 index 0000000000..5dd349420c Binary files /dev/null and b/resources/builtin/projects/fa-twitter.png differ diff --git a/resources/builtin/projects/fa-umbrella.png b/resources/builtin/projects/fa-umbrella.png new file mode 100644 index 0000000000..5369f45840 Binary files /dev/null and b/resources/builtin/projects/fa-umbrella.png differ diff --git a/resources/builtin/projects/fa-university.png b/resources/builtin/projects/fa-university.png new file mode 100644 index 0000000000..5d523182e7 Binary files /dev/null and b/resources/builtin/projects/fa-university.png differ diff --git a/resources/builtin/projects/fa-user-secret.png b/resources/builtin/projects/fa-user-secret.png new file mode 100644 index 0000000000..c84267103c Binary files /dev/null and b/resources/builtin/projects/fa-user-secret.png differ diff --git a/resources/builtin/projects/fa-user.png b/resources/builtin/projects/fa-user.png new file mode 100644 index 0000000000..62c77a6729 Binary files /dev/null and b/resources/builtin/projects/fa-user.png differ diff --git a/resources/builtin/projects/fa-users.png b/resources/builtin/projects/fa-users.png new file mode 100644 index 0000000000..93d0a2f8bc Binary files /dev/null and b/resources/builtin/projects/fa-users.png differ diff --git a/resources/builtin/projects/fa-warning.png b/resources/builtin/projects/fa-warning.png new file mode 100644 index 0000000000..a950cb7e8e Binary files /dev/null and b/resources/builtin/projects/fa-warning.png differ diff --git a/resources/builtin/projects/fa-wheelchair.png b/resources/builtin/projects/fa-wheelchair.png new file mode 100644 index 0000000000..602f744a46 Binary files /dev/null and b/resources/builtin/projects/fa-wheelchair.png differ diff --git a/resources/builtin/projects/fa-windows.png b/resources/builtin/projects/fa-windows.png new file mode 100644 index 0000000000..5e7c6e6acf Binary files /dev/null and b/resources/builtin/projects/fa-windows.png differ diff --git a/resources/celerity/map.php b/resources/celerity/map.php index bb30c70582..68c281faa5 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -7,8 +7,8 @@ */ return array( 'names' => array( - 'core.pkg.css' => '1eed0b4f', - 'core.pkg.js' => '6ae03393', + 'core.pkg.css' => '1d1e9a3a', + 'core.pkg.js' => '573e6664', 'darkconsole.pkg.js' => 'e7393ebb', 'differential.pkg.css' => '2de124c9', 'differential.pkg.js' => 'f83532f8', @@ -32,11 +32,11 @@ return array( 'rsrc/css/aphront/typeahead.css' => '0e403212', 'rsrc/css/application/almanac/almanac.css' => 'dbb9b3af', 'rsrc/css/application/auth/auth.css' => '0877ed6e', - 'rsrc/css/application/base/main-menu-view.css' => '2f670a96', + 'rsrc/css/application/base/main-menu-view.css' => 'd00a795a', 'rsrc/css/application/base/notification-menu.css' => 'f31c0bde', 'rsrc/css/application/base/phabricator-application-launch-view.css' => '95351601', - 'rsrc/css/application/base/phui-theme.css' => '6b451f24', - 'rsrc/css/application/base/standard-page-view.css' => '3c99cdf4', + 'rsrc/css/application/base/phui-theme.css' => '981a58f8', + 'rsrc/css/application/base/standard-page-view.css' => '7b0d68d8', 'rsrc/css/application/chatlog/chatlog.css' => 'd295b020', 'rsrc/css/application/conduit/conduit-api.css' => '7bc725c4', 'rsrc/css/application/config/config-options.css' => '0ede4c9b', @@ -80,8 +80,8 @@ return array( 'rsrc/css/application/objectselector/object-selector.css' => '85ee8ce6', 'rsrc/css/application/owners/owners-path-editor.css' => '2f00933b', 'rsrc/css/application/paste/paste.css' => 'a5157c48', - 'rsrc/css/application/people/people-profile.css' => '25970776', - 'rsrc/css/application/phame/phame.css' => 'dac8fdf2', + 'rsrc/css/application/people/people-profile.css' => 'fa2069ec', + 'rsrc/css/application/phame/phame.css' => '6d5b3682', 'rsrc/css/application/pholio/pholio-edit.css' => '3ad9d1ee', 'rsrc/css/application/pholio/pholio-inline-comments.css' => '8e545e49', 'rsrc/css/application/pholio/pholio.css' => '95174bdd', @@ -102,9 +102,9 @@ return array( 'rsrc/css/application/tokens/tokens.css' => '3d0f239e', 'rsrc/css/application/uiexample/example.css' => '528b19de', 'rsrc/css/core/core.css' => 'a76cefc9', - 'rsrc/css/core/remarkup.css' => 'b6ad82e4', + 'rsrc/css/core/remarkup.css' => '64277c02', 'rsrc/css/core/syntax.css' => '9fd11da8', - 'rsrc/css/core/z-index.css' => '57ddcaa2', + 'rsrc/css/core/z-index.css' => 'a36a45da', 'rsrc/css/diviner/diviner-shared.css' => 'aa3656aa', 'rsrc/css/font/font-aleo.css' => '8bdb2835', 'rsrc/css/font/font-awesome.css' => 'c43323c5', @@ -112,7 +112,7 @@ return array( 'rsrc/css/font/phui-font-icon-base.css' => 'ecbbb4c2', 'rsrc/css/layout/phabricator-filetree-view.css' => 'fccf9f82', 'rsrc/css/layout/phabricator-hovercard-view.css' => '1239cd52', - 'rsrc/css/layout/phabricator-side-menu-view.css' => '91b7a42c', + 'rsrc/css/layout/phabricator-side-menu-view.css' => '3a3d9f41', 'rsrc/css/layout/phabricator-source-code-view.css' => 'cbeef983', 'rsrc/css/phui/calendar/phui-calendar-day.css' => 'd1cf6f93', 'rsrc/css/phui/calendar/phui-calendar-list.css' => 'c1c7f338', @@ -122,7 +122,7 @@ return array( 'rsrc/css/phui/phui-action-panel.css' => '91c7b835', 'rsrc/css/phui/phui-badge.css' => 'f25c3476', 'rsrc/css/phui/phui-big-info-view.css' => 'bd903741', - 'rsrc/css/phui/phui-box.css' => 'a5bb366d', + 'rsrc/css/phui/phui-box.css' => '10939564', 'rsrc/css/phui/phui-button.css' => '16020a60', 'rsrc/css/phui/phui-crumbs-view.css' => '414406b5', 'rsrc/css/phui/phui-document-pro.css' => '8799acf7', @@ -134,7 +134,7 @@ return array( 'rsrc/css/phui/phui-form.css' => '0b98e572', 'rsrc/css/phui/phui-header-view.css' => '55bb32dd', 'rsrc/css/phui/phui-icon-set-selector.css' => '1ab67aad', - 'rsrc/css/phui/phui-icon.css' => 'b0a6b1b6', + 'rsrc/css/phui/phui-icon.css' => '3f33ab57', 'rsrc/css/phui/phui-image-mask.css' => '5a8b09c8', 'rsrc/css/phui/phui-info-panel.css' => '27ea50a1', 'rsrc/css/phui/phui-info-view.css' => '6d7c3509', @@ -143,6 +143,7 @@ return array( 'rsrc/css/phui/phui-object-item-list-view.css' => '26c30d3f', 'rsrc/css/phui/phui-pager.css' => 'bea33d23', 'rsrc/css/phui/phui-pinboard-view.css' => '2495140e', + 'rsrc/css/phui/phui-profile-menu.css' => '43826c43', 'rsrc/css/phui/phui-property-list-view.css' => '27b2849e', 'rsrc/css/phui/phui-remarkup-preview.css' => '1a8f2591', 'rsrc/css/phui/phui-spacing.css' => '042804d6', @@ -151,12 +152,10 @@ return array( 'rsrc/css/phui/phui-text.css' => 'cf019f54', 'rsrc/css/phui/phui-timeline-view.css' => '2efceff8', 'rsrc/css/phui/phui-two-column-view.css' => '39ecafb1', - 'rsrc/css/phui/phui-workboard-view.css' => '24fe2a66', + 'rsrc/css/phui/phui-workboard-view.css' => 'f488d036', 'rsrc/css/phui/phui-workpanel-view.css' => 'adec7699', 'rsrc/css/sprite-login.css' => '60e8560e', - 'rsrc/css/sprite-main-header.css' => 'f07bbb87', 'rsrc/css/sprite-menu.css' => '9dd65b92', - 'rsrc/css/sprite-projects.css' => 'e5ad842a', 'rsrc/css/sprite-tokens.css' => '4f399012', 'rsrc/externals/font/aleo/aleo-bold.eot' => 'd3d3bed7', 'rsrc/externals/font/aleo/aleo-bold.svg' => '45899c8e', @@ -248,9 +247,9 @@ return array( 'rsrc/externals/javelin/lib/control/typeahead/Typeahead.js' => '70baed2f', 'rsrc/externals/javelin/lib/control/typeahead/normalizer/TypeaheadNormalizer.js' => 'e6e25838', 'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadCompositeSource.js' => '503e17fd', - 'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadOnDemandSource.js' => '8b3fd187', + 'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadOnDemandSource.js' => '013ffff9', 'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadPreloadedSource.js' => '54f314a0', - 'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadSource.js' => '2818f5ce', + 'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadSource.js' => '1bc11c4a', 'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadStaticSource.js' => '6c0e62fa', 'rsrc/externals/raphael/g.raphael.js' => '40dde778', 'rsrc/externals/raphael/g.raphael.line.js' => '40da039e', @@ -335,11 +334,8 @@ return array( 'rsrc/image/phrequent_inactive.png' => 'bfc15a69', 'rsrc/image/sprite-login-X2.png' => 'e3991e37', 'rsrc/image/sprite-login.png' => '03d5af29', - 'rsrc/image/sprite-main-header.png' => '3673af44', 'rsrc/image/sprite-menu-X2.png' => 'cfd8fca5', 'rsrc/image/sprite-menu.png' => 'd7a99faa', - 'rsrc/image/sprite-projects-X2.png' => '853552c7', - 'rsrc/image/sprite-projects.png' => 'b9dd74b8', 'rsrc/image/sprite-tokens-X2.png' => '348f1745', 'rsrc/image/sprite-tokens.png' => 'ce0b62be', 'rsrc/image/texture/card-gradient.png' => '815f26e8', @@ -397,9 +393,9 @@ return array( 'rsrc/js/application/diffusion/behavior-pull-lastmodified.js' => 'f01586dc', 'rsrc/js/application/doorkeeper/behavior-doorkeeper-tag.js' => 'e5822781', 'rsrc/js/application/drydock/drydock-live-operation-status.js' => '901935ef', - 'rsrc/js/application/files/behavior-icon-composer.js' => '8ef9ab58', + 'rsrc/js/application/files/behavior-icon-composer.js' => '8499b6ab', 'rsrc/js/application/files/behavior-launch-icon-composer.js' => '48086888', - 'rsrc/js/application/herald/HeraldRuleEditor.js' => '5bd8f385', + 'rsrc/js/application/herald/HeraldRuleEditor.js' => '746ca158', 'rsrc/js/application/herald/PathTypeahead.js' => 'f7fc67ec', 'rsrc/js/application/herald/herald-rule-editor.js' => '7ebaeed3', 'rsrc/js/application/maniphest/behavior-batch-editor.js' => '782ab6e7', @@ -457,7 +453,7 @@ return array( 'rsrc/js/core/KeyboardShortcutManager.js' => 'c1700f6f', 'rsrc/js/core/MultirowRowManager.js' => 'b5d57730', 'rsrc/js/core/Notification.js' => 'ccf1cbf8', - 'rsrc/js/core/Prefab.js' => '666c80c5', + 'rsrc/js/core/Prefab.js' => 'e67df814', 'rsrc/js/core/ShapedRequest.js' => '7cbe244b', 'rsrc/js/core/TextAreaUtils.js' => '9e54692d', 'rsrc/js/core/Title.js' => 'df5e11d2', @@ -487,7 +483,7 @@ return array( 'rsrc/js/core/behavior-object-selector.js' => '49b73b36', 'rsrc/js/core/behavior-oncopy.js' => '2926fff2', 'rsrc/js/core/behavior-phabricator-nav.js' => '56a1ca03', - 'rsrc/js/core/behavior-phabricator-remarkup-assist.js' => 'b60b6d9b', + 'rsrc/js/core/behavior-phabricator-remarkup-assist.js' => '340c8eff', 'rsrc/js/core/behavior-refresh-csrf.js' => 'ab2f381b', 'rsrc/js/core/behavior-remarkup-preview.js' => '4b700e9e', 'rsrc/js/core/behavior-reorder-applications.js' => '76b9fc3e', @@ -504,8 +500,10 @@ return array( 'rsrc/js/core/phtize.js' => 'd254d646', 'rsrc/js/phui/behavior-phui-dropdown-menu.js' => '54733475', 'rsrc/js/phui/behavior-phui-object-box-tabs.js' => '2bfa2836', + 'rsrc/js/phui/behavior-phui-profile-menu.js' => 'bfc2e675', 'rsrc/js/phuix/PHUIXActionListView.js' => 'b5c256b8', 'rsrc/js/phuix/PHUIXActionView.js' => '8cf6d262', + 'rsrc/js/phuix/PHUIXAutocomplete.js' => '21dc9144', 'rsrc/js/phuix/PHUIXDropdownMenu.js' => 'bd4c8dca', 'rsrc/js/phuix/PHUIXFormControl.js' => '8fba1997', 'rsrc/js/phuix/PHUIXIconView.js' => 'bff6884b', @@ -554,7 +552,7 @@ return array( 'global-drag-and-drop-css' => '697324ad', 'harbormaster-css' => 'b0758ca5', 'herald-css' => '826075fa', - 'herald-rule-editor' => '5bd8f385', + 'herald-rule-editor' => '746ca158', 'herald-test-css' => 'a52e323e', 'inline-comment-summary-css' => '51efda3a', 'javelin-aphlict' => '5359e785', @@ -613,7 +611,7 @@ return array( 'javelin-behavior-herald-rule-editor' => '7ebaeed3', 'javelin-behavior-high-security-warning' => 'a464fe03', 'javelin-behavior-history-install' => '7ee2b591', - 'javelin-behavior-icon-composer' => '8ef9ab58', + 'javelin-behavior-icon-composer' => '8499b6ab', 'javelin-behavior-launch-icon-composer' => '48086888', 'javelin-behavior-lightbox-attachments' => 'f8ba29d7', 'javelin-behavior-line-chart' => '88f0c5b3', @@ -639,7 +637,7 @@ return array( 'javelin-behavior-phabricator-notification-example' => '8ce821c5', 'javelin-behavior-phabricator-object-selector' => '49b73b36', 'javelin-behavior-phabricator-oncopy' => '2926fff2', - 'javelin-behavior-phabricator-remarkup-assist' => 'b60b6d9b', + 'javelin-behavior-phabricator-remarkup-assist' => '340c8eff', 'javelin-behavior-phabricator-reveal-content' => '60821bc7', 'javelin-behavior-phabricator-search-typeahead' => '0b7a4f6e', 'javelin-behavior-phabricator-show-older-transactions' => 'dbbf48b6', @@ -651,6 +649,7 @@ return array( 'javelin-behavior-pholio-mock-view' => 'fbe497e7', 'javelin-behavior-phui-dropdown-menu' => '54733475', 'javelin-behavior-phui-object-box-tabs' => '2bfa2836', + 'javelin-behavior-phui-profile-menu' => 'bfc2e675', 'javelin-behavior-policy-control' => 'ae45872f', 'javelin-behavior-policy-rule-editor' => '5e9f347c', 'javelin-behavior-project-boards' => 'ba4fa35c', @@ -707,9 +706,9 @@ return array( 'javelin-typeahead' => '70baed2f', 'javelin-typeahead-composite-source' => '503e17fd', 'javelin-typeahead-normalizer' => 'e6e25838', - 'javelin-typeahead-ondemand-source' => '8b3fd187', + 'javelin-typeahead-ondemand-source' => '013ffff9', 'javelin-typeahead-preloaded-source' => '54f314a0', - 'javelin-typeahead-source' => '2818f5ce', + 'javelin-typeahead-source' => '1bc11c4a', 'javelin-typeahead-static-source' => '6c0e62fa', 'javelin-uri' => 'c989ade3', 'javelin-util' => '93cc50d6', @@ -731,7 +730,7 @@ return array( 'owners-path-editor-css' => '2f00933b', 'paste-css' => 'a5157c48', 'path-typeahead' => 'f7fc67ec', - 'people-profile-css' => '25970776', + 'people-profile-css' => 'fa2069ec', 'phabricator-action-list-view-css' => 'c5eba19d', 'phabricator-application-launch-view-css' => '95351601', 'phabricator-busy' => '59a7976a', @@ -751,21 +750,21 @@ return array( 'phabricator-hovercard-view-css' => '1239cd52', 'phabricator-keyboard-shortcut' => '1ae869f2', 'phabricator-keyboard-shortcut-manager' => 'c1700f6f', - 'phabricator-main-menu-view' => '2f670a96', + 'phabricator-main-menu-view' => 'd00a795a', 'phabricator-nav-view-css' => 'a24cb589', 'phabricator-notification' => 'ccf1cbf8', 'phabricator-notification-css' => '9c279160', 'phabricator-notification-menu-css' => 'f31c0bde', 'phabricator-object-selector-css' => '85ee8ce6', 'phabricator-phtize' => 'd254d646', - 'phabricator-prefab' => '666c80c5', - 'phabricator-remarkup-css' => 'b6ad82e4', + 'phabricator-prefab' => 'e67df814', + 'phabricator-remarkup-css' => '64277c02', 'phabricator-search-results-css' => '7dea472c', 'phabricator-shaped-request' => '7cbe244b', - 'phabricator-side-menu-view-css' => '91b7a42c', + 'phabricator-side-menu-view-css' => '3a3d9f41', 'phabricator-slowvote-css' => 'da0afb1b', 'phabricator-source-code-view-css' => 'cbeef983', - 'phabricator-standard-page-view' => '3c99cdf4', + 'phabricator-standard-page-view' => '7b0d68d8', 'phabricator-textareautils' => '9e54692d', 'phabricator-title' => 'df5e11d2', 'phabricator-tooltip' => '1d298e3a', @@ -780,8 +779,8 @@ return array( 'phabricator-uiexample-reactor-select' => 'a155550f', 'phabricator-uiexample-reactor-sendclass' => '1def2711', 'phabricator-uiexample-reactor-sendproperties' => 'b1f0ccee', - 'phabricator-zindex-css' => '57ddcaa2', - 'phame-css' => 'dac8fdf2', + 'phabricator-zindex-css' => 'a36a45da', + 'phame-css' => '6d5b3682', 'pholio-css' => '95174bdd', 'pholio-edit-css' => '3ad9d1ee', 'pholio-inline-comments-css' => '8e545e49', @@ -793,7 +792,7 @@ return array( 'phui-action-panel-css' => '91c7b835', 'phui-badge-view-css' => 'f25c3476', 'phui-big-info-view-css' => 'bd903741', - 'phui-box-css' => 'a5bb366d', + 'phui-box-css' => '10939564', 'phui-button-css' => '16020a60', 'phui-calendar-css' => 'ccabe893', 'phui-calendar-day-css' => 'd1cf6f93', @@ -810,7 +809,7 @@ return array( 'phui-form-view-css' => '4a1a0f5e', 'phui-header-view-css' => '55bb32dd', 'phui-icon-set-selector-css' => '1ab67aad', - 'phui-icon-view-css' => 'b0a6b1b6', + 'phui-icon-view-css' => '3f33ab57', 'phui-image-mask-css' => '5a8b09c8', 'phui-info-panel-css' => '27ea50a1', 'phui-info-view-css' => '6d7c3509', @@ -820,19 +819,21 @@ return array( 'phui-object-item-list-view-css' => '26c30d3f', 'phui-pager-css' => 'bea33d23', 'phui-pinboard-view-css' => '2495140e', + 'phui-profile-menu-css' => '43826c43', 'phui-property-list-view-css' => '27b2849e', 'phui-remarkup-preview-css' => '1a8f2591', 'phui-spacing-css' => '042804d6', 'phui-status-list-view-css' => '888cedb8', 'phui-tag-view-css' => 'e60e227b', 'phui-text-css' => 'cf019f54', - 'phui-theme-css' => '6b451f24', + 'phui-theme-css' => '981a58f8', 'phui-timeline-view-css' => '2efceff8', 'phui-two-column-view-css' => '39ecafb1', - 'phui-workboard-view-css' => '24fe2a66', + 'phui-workboard-view-css' => 'f488d036', 'phui-workpanel-view-css' => 'adec7699', 'phuix-action-list-view' => 'b5c256b8', 'phuix-action-view' => '8cf6d262', + 'phuix-autocomplete' => '21dc9144', 'phuix-dropdown-menu' => 'bd4c8dca', 'phuix-form-control-view' => '8fba1997', 'phuix-icon-view' => 'bff6884b', @@ -849,9 +850,7 @@ return array( 'releeph-request-typeahead-css' => '667a48ae', 'setup-issue-css' => 'db7e9c40', 'sprite-login-css' => '60e8560e', - 'sprite-main-header-css' => 'f07bbb87', 'sprite-menu-css' => '9dd65b92', - 'sprite-projects-css' => 'e5ad842a', 'sprite-tokens-css' => '4f399012', 'syntax-highlighting-css' => '9fd11da8', 'tokens-css' => '3d0f239e', @@ -859,6 +858,12 @@ return array( 'unhandled-exception-css' => '4c96257a', ), 'requires' => array( + '013ffff9' => array( + 'javelin-install', + 'javelin-util', + 'javelin-request', + 'javelin-typeahead-source', + ), '01774ab2' => array( 'javelin-dom', 'javelin-util', @@ -946,6 +951,12 @@ return array( 'javelin-util', 'phabricator-keyboard-shortcut-manager', ), + '1bc11c4a' => array( + 'javelin-install', + 'javelin-util', + 'javelin-dom', + 'javelin-typeahead-normalizer', + ), '1d298e3a' => array( 'javelin-install', 'javelin-util', @@ -988,6 +999,12 @@ return array( 'javelin-stratcom', 'conpherence-thread-manager', ), + '21dc9144' => array( + 'javelin-install', + 'javelin-dom', + 'phuix-icon-view', + 'phabricator-prefab', + ), '2290aeef' => array( 'javelin-install', 'javelin-dom', @@ -1005,12 +1022,6 @@ return array( 'phabricator-drag-and-drop-file-upload', 'phabricator-draggable-list', ), - '2818f5ce' => array( - 'javelin-install', - 'javelin-util', - 'javelin-dom', - 'javelin-typeahead-normalizer', - ), '2926fff2' => array( 'javelin-behavior', 'javelin-dom', @@ -1038,9 +1049,6 @@ return array( 'javelin-install', 'javelin-event', ), - '2f670a96' => array( - 'phui-theme-css', - ), '327a00d1' => array( 'javelin-behavior', 'javelin-stratcom', @@ -1050,6 +1058,16 @@ return array( '331b1611' => array( 'javelin-install', ), + '340c8eff' => array( + 'javelin-behavior', + 'javelin-stratcom', + 'javelin-dom', + 'phabricator-phtize', + 'phabricator-textareautils', + 'javelin-workflow', + 'javelin-vector', + 'phuix-autocomplete', + ), '3ab51e2c' => array( 'javelin-behavior', 'javelin-behavior-device', @@ -1227,15 +1245,6 @@ return array( 'javelin-uri', 'javelin-routable', ), - '5bd8f385' => array( - 'multirow-row-manager', - 'javelin-install', - 'javelin-util', - 'javelin-dom', - 'javelin-stratcom', - 'javelin-json', - 'phabricator-prefab', - ), '5c54cbf3' => array( 'javelin-behavior', 'javelin-stratcom', @@ -1293,18 +1302,6 @@ return array( 'javelin-vector', 'differential-inline-comment-editor', ), - '666c80c5' => array( - 'javelin-install', - 'javelin-util', - 'javelin-dom', - 'javelin-typeahead', - 'javelin-tokenizer', - 'javelin-typeahead-preloaded-source', - 'javelin-typeahead-ondemand-source', - 'javelin-dom', - 'javelin-stratcom', - 'javelin-util', - ), '66dd6e9e' => array( 'javelin-behavior', 'javelin-behavior-device', @@ -1364,6 +1361,15 @@ return array( 'javelin-vector', 'javelin-dom', ), + '746ca158' => array( + 'multirow-row-manager', + 'javelin-install', + 'javelin-util', + 'javelin-dom', + 'javelin-stratcom', + 'javelin-json', + 'phabricator-prefab', + ), '76b9fc3e' => array( 'javelin-behavior', 'javelin-stratcom', @@ -1434,6 +1440,11 @@ return array( 'javelin-behavior', 'javelin-scrollbar', ), + '8499b6ab' => array( + 'javelin-behavior', + 'javelin-dom', + 'javelin-stratcom', + ), '85ea0626' => array( 'javelin-install', ), @@ -1481,12 +1492,6 @@ return array( 'javelin-stratcom', 'javelin-vector', ), - '8b3fd187' => array( - 'javelin-install', - 'javelin-util', - 'javelin-request', - 'javelin-typeahead-source', - ), '8bdb2835' => array( 'phui-fontkit-css', ), @@ -1506,11 +1511,6 @@ return array( 'javelin-stratcom', 'javelin-install', ), - '8ef9ab58' => array( - 'javelin-behavior', - 'javelin-dom', - 'javelin-stratcom', - ), '8fba1997' => array( 'javelin-install', 'javelin-dom', @@ -1742,15 +1742,6 @@ return array( 'javelin-dom', 'javelin-util', ), - 'b60b6d9b' => array( - 'javelin-behavior', - 'javelin-stratcom', - 'javelin-dom', - 'phabricator-phtize', - 'phabricator-textareautils', - 'javelin-workflow', - 'javelin-vector', - ), 'b6993408' => array( 'javelin-behavior', 'javelin-stratcom', @@ -1783,6 +1774,11 @@ return array( 'javelin-util', 'javelin-request', ), + 'bfc2e675' => array( + 'javelin-behavior', + 'javelin-stratcom', + 'javelin-dom', + ), 'bff6884b' => array( 'javelin-install', 'javelin-dom', @@ -1853,6 +1849,9 @@ return array( 'javelin-workflow', 'phabricator-drag-and-drop-file-upload', ), + 'd00a795a' => array( + 'phui-theme-css', + ), 'd19198c8' => array( 'javelin-install', 'javelin-dom', @@ -1966,6 +1965,18 @@ return array( 'javelin-workflow', 'javelin-magical-init', ), + 'e67df814' => array( + 'javelin-install', + 'javelin-util', + 'javelin-dom', + 'javelin-typeahead', + 'javelin-tokenizer', + 'javelin-typeahead-preloaded-source', + 'javelin-typeahead-ondemand-source', + 'javelin-dom', + 'javelin-stratcom', + 'javelin-util', + ), 'e6e25838' => array( 'javelin-install', ), @@ -2127,6 +2138,7 @@ return array( 'phui-spacing-css', 'phui-form-css', 'phui-icon-view-css', + 'phui-profile-menu-css', 'phabricator-application-launch-view-css', 'phabricator-action-list-view-css', 'phui-property-list-view-css', diff --git a/resources/celerity/packages.php b/resources/celerity/packages.php index bb97cb889e..5a3e296a8c 100644 --- a/resources/celerity/packages.php +++ b/resources/celerity/packages.php @@ -116,6 +116,7 @@ return array( 'phui-spacing-css', 'phui-form-css', 'phui-icon-view-css', + 'phui-profile-menu-css', 'phabricator-application-launch-view-css', 'phabricator-action-list-view-css', diff --git a/resources/sprite/main_header/applebloom.png b/resources/sprite/main_header/applebloom.png deleted file mode 100644 index 29721ef8fd..0000000000 Binary files a/resources/sprite/main_header/applebloom.png and /dev/null differ diff --git a/resources/sprite/main_header/blindigo.png b/resources/sprite/main_header/blindigo.png deleted file mode 100644 index 827eca8887..0000000000 Binary files a/resources/sprite/main_header/blindigo.png and /dev/null differ diff --git a/resources/sprite/main_header/blue.png b/resources/sprite/main_header/blue.png deleted file mode 100644 index 7183340432..0000000000 Binary files a/resources/sprite/main_header/blue.png and /dev/null differ diff --git a/resources/sprite/main_header/dark.png b/resources/sprite/main_header/dark.png deleted file mode 100644 index f676a0d1b8..0000000000 Binary files a/resources/sprite/main_header/dark.png and /dev/null differ diff --git a/resources/sprite/main_header/fluttershy.png b/resources/sprite/main_header/fluttershy.png deleted file mode 100644 index 796158d39b..0000000000 Binary files a/resources/sprite/main_header/fluttershy.png and /dev/null differ diff --git a/resources/sprite/main_header/green.png b/resources/sprite/main_header/green.png deleted file mode 100644 index 6c84d1deaa..0000000000 Binary files a/resources/sprite/main_header/green.png and /dev/null differ diff --git a/resources/sprite/main_header/indigo.png b/resources/sprite/main_header/indigo.png deleted file mode 100644 index ac38dfbdcd..0000000000 Binary files a/resources/sprite/main_header/indigo.png and /dev/null differ diff --git a/resources/sprite/main_header/light.png b/resources/sprite/main_header/light.png deleted file mode 100644 index cd786082f0..0000000000 Binary files a/resources/sprite/main_header/light.png and /dev/null differ diff --git a/resources/sprite/main_header/nightmaremoon.png b/resources/sprite/main_header/nightmaremoon.png deleted file mode 100644 index 2e98550795..0000000000 Binary files a/resources/sprite/main_header/nightmaremoon.png and /dev/null differ diff --git a/resources/sprite/main_header/red.png b/resources/sprite/main_header/red.png deleted file mode 100644 index 2620221ec6..0000000000 Binary files a/resources/sprite/main_header/red.png and /dev/null differ diff --git a/resources/sprite/main_header/scootaloo.png b/resources/sprite/main_header/scootaloo.png deleted file mode 100644 index 32e724ec5e..0000000000 Binary files a/resources/sprite/main_header/scootaloo.png and /dev/null differ diff --git a/resources/sprite/main_header/yellow.png b/resources/sprite/main_header/yellow.png deleted file mode 100644 index a8a4d67f0b..0000000000 Binary files a/resources/sprite/main_header/yellow.png and /dev/null differ diff --git a/resources/sprite/manifest/main-header.json b/resources/sprite/manifest/main-header.json deleted file mode 100644 index 0e3f6a4404..0000000000 --- a/resources/sprite/manifest/main-header.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "version": 1, - "sprites": { - "main-header-applebloom": { - "name": "main-header-applebloom", - "rule": ".phui-theme-applebloom .phabricator-main-menu-background", - "hash": "64822776b129e724709983db1ac5a712" - }, - "main-header-blindigo": { - "name": "main-header-blindigo", - "rule": ".phui-theme-blindigo .phabricator-main-menu-background", - "hash": "8c4f5b1f1f3faceb6ca6e8278a1b082f" - }, - "main-header-blue": { - "name": "main-header-blue", - "rule": ".phui-theme-blue .phabricator-main-menu-background", - "hash": "b5dd317b7bd35e0592b3f4b66267437c" - }, - "main-header-dark": { - "name": "main-header-dark", - "rule": ".phui-theme-dark .phabricator-main-menu-background", - "hash": "817815d84c0c935b4875f6ecc7dbb526" - }, - "main-header-fluttershy": { - "name": "main-header-fluttershy", - "rule": ".phui-theme-fluttershy .phabricator-main-menu-background", - "hash": "55d4e9f813cf354693290105cf83cf78" - }, - "main-header-green": { - "name": "main-header-green", - "rule": ".phui-theme-green .phabricator-main-menu-background", - "hash": "c230f09e307d167fab3ea0d8c3b33755" - }, - "main-header-indigo": { - "name": "main-header-indigo", - "rule": ".phui-theme-indigo .phabricator-main-menu-background", - "hash": "a27394ff1eff4d24398ec57e54d7f5fd" - }, - "main-header-light": { - "name": "main-header-light", - "rule": ".phui-theme-light .phabricator-main-menu-background", - "hash": "3c41fbfbe13cae2451467a1e307115aa" - }, - "main-header-nightmaremoon": { - "name": "main-header-nightmaremoon", - "rule": ".phui-theme-nightmaremoon .phabricator-main-menu-background", - "hash": "9e7cc7b18d2132d2dd47586ba0cd6400" - }, - "main-header-red": { - "name": "main-header-red", - "rule": ".phui-theme-red .phabricator-main-menu-background", - "hash": "3f12cc098afddb8e6c830ef761dcaa61" - }, - "main-header-scootaloo": { - "name": "main-header-scootaloo", - "rule": ".phui-theme-scootaloo .phabricator-main-menu-background", - "hash": "8cedc359dccab1bbd49cbc69940f566a" - }, - "main-header-yellow": { - "name": "main-header-yellow", - "rule": ".phui-theme-yellow .phabricator-main-menu-background", - "hash": "d920e70a6d2662cfb83e1d7e4b4000fd" - } - }, - "scales": [ - 1 - ], - "header": "\/**\n * @provides sprite-main-header-css\n * @generated\n *\/\n\n.sprite-main-header {\n background-image: url(\/rsrc\/image\/sprite-main-header.png);\n background-repeat: repeat-x;\n}\n\n\n", - "type": "repeat-x" -} diff --git a/resources/sprite/manifest/projects.json b/resources/sprite/manifest/projects.json deleted file mode 100644 index 592583f0b1..0000000000 --- a/resources/sprite/manifest/projects.json +++ /dev/null @@ -1,371 +0,0 @@ -{ - "version": 1, - "sprites": { - "projects-8ball": { - "name": "projects-8ball", - "rule": ".projects-8ball", - "hash": "1571c4d51926d3af7711b825c5816e2e" - }, - "projects-alien": { - "name": "projects-alien", - "rule": ".projects-alien", - "hash": "384f920ae335dca04edaf29663d3a074" - }, - "projects-announce": { - "name": "projects-announce", - "rule": ".projects-announce", - "hash": "94329cedd509fc27a6fb577927581118" - }, - "projects-art": { - "name": "projects-art", - "rule": ".projects-art", - "hash": "85c545e5130f00ff1b93c0af0d540974" - }, - "projects-award": { - "name": "projects-award", - "rule": ".projects-award", - "hash": "fad6d89e4938e16f22f3c9db7cf5d696" - }, - "projects-bacon": { - "name": "projects-bacon", - "rule": ".projects-bacon", - "hash": "f6300cdfa5a96a223f53f13dd0d3acc3" - }, - "projects-bandaid": { - "name": "projects-bandaid", - "rule": ".projects-bandaid", - "hash": "c463dffa161997277fc6697155f4085b" - }, - "projects-beer": { - "name": "projects-beer", - "rule": ".projects-beer", - "hash": "81c7580f322d9fb40c77db56cd92d61d" - }, - "projects-bomb": { - "name": "projects-bomb", - "rule": ".projects-bomb", - "hash": "1123da7cc56313891c9979b004cc02f7" - }, - "projects-briefcase": { - "name": "projects-briefcase", - "rule": ".projects-briefcase", - "hash": "9b4b413ddb250ce1d3fbe18a5a5698cd" - }, - "projects-bug": { - "name": "projects-bug", - "rule": ".projects-bug", - "hash": "9678702aed00c4779759ebbdfe97fe48" - }, - "projects-calendar": { - "name": "projects-calendar", - "rule": ".projects-calendar", - "hash": "e7dc5d1b11fc55ed239fcbfe527ed0e7" - }, - "projects-cloud": { - "name": "projects-cloud", - "rule": ".projects-cloud", - "hash": "d38bf58580b3c36fbd3149a13f7d0e5e" - }, - "projects-coffee": { - "name": "projects-coffee", - "rule": ".projects-coffee", - "hash": "a9c10862139d8e7f56c9f892496f9666" - }, - "projects-creditcard": { - "name": "projects-creditcard", - "rule": ".projects-creditcard", - "hash": "db2c179cb4935da8b9950ac30da8c0d1" - }, - "projects-death": { - "name": "projects-death", - "rule": ".projects-death", - "hash": "cdea72dfdcb3fc64873b9fff78addb3c" - }, - "projects-desktop": { - "name": "projects-desktop", - "rule": ".projects-desktop", - "hash": "19d2ef34e3dd53615cdad91eb987d6fe" - }, - "projects-dropbox": { - "name": "projects-dropbox", - "rule": ".projects-dropbox", - "hash": "10231bf468769b96ed40cf983abfa269" - }, - "projects-education": { - "name": "projects-education", - "rule": ".projects-education", - "hash": "ce3d0ca75d519b2ac427a690d30475f8" - }, - "projects-experimental": { - "name": "projects-experimental", - "rule": ".projects-experimental", - "hash": "311ef712f8daca057c20c8fd78fa77ce" - }, - "projects-fa-briefcase": { - "name": "projects-fa-briefcase", - "rule": ".projects-fa-briefcase", - "hash": "f3dd4c94ce9f1cc74068af3ea9a4bc65" - }, - "projects-fa-bug": { - "name": "projects-fa-bug", - "rule": ".projects-fa-bug", - "hash": "e85895919b8fdbdbbcf43e476e70adcc" - }, - "projects-fa-building": { - "name": "projects-fa-building", - "rule": ".projects-fa-building", - "hash": "5ba0272ba1d3dee530cf72bd14b060e1" - }, - "projects-fa-calendar": { - "name": "projects-fa-calendar", - "rule": ".projects-fa-calendar", - "hash": "38b05d30e454285b56c7021d19ca7c93" - }, - "projects-fa-cloud": { - "name": "projects-fa-cloud", - "rule": ".projects-fa-cloud", - "hash": "9202ca72998bb07180464064258f43ff" - }, - "projects-fa-credit-card": { - "name": "projects-fa-credit-card", - "rule": ".projects-fa-credit-card", - "hash": "0b73456cbdb383ae2b211c7c8b90b712" - }, - "projects-fa-envelope": { - "name": "projects-fa-envelope", - "rule": ".projects-fa-envelope", - "hash": "73a2c4560e4d12125dbb3a3d1cab3f3f" - }, - "projects-fa-flag-checkered": { - "name": "projects-fa-flag-checkered", - "rule": ".projects-fa-flag-checkered", - "hash": "57b7474e5d81c84fa5020cb57f82d1ca" - }, - "projects-fa-flask": { - "name": "projects-fa-flask", - "rule": ".projects-fa-flask", - "hash": "ae9edea912a19440c15fefdbf728def4" - }, - "projects-fa-folder": { - "name": "projects-fa-folder", - "rule": ".projects-fa-folder", - "hash": "d3c6eb3334d6b6f1b8a1159d9d9e7397" - }, - "projects-fa-lock": { - "name": "projects-fa-lock", - "rule": ".projects-fa-lock", - "hash": "fa1eabe664aa26fa4732a18849a4d581" - }, - "projects-fa-tags": { - "name": "projects-fa-tags", - "rule": ".projects-fa-tags", - "hash": "f167c28072cf39a388ae0056d5f5f757" - }, - "projects-fa-trash-o": { - "name": "projects-fa-trash-o", - "rule": ".projects-fa-trash-o", - "hash": "82fb2b427b0b331652d19fd3654905a2" - }, - "projects-fa-truck": { - "name": "projects-fa-truck", - "rule": ".projects-fa-truck", - "hash": "89136aa2b52a6543b7c20dbdf0727191" - }, - "projects-fa-umbrella": { - "name": "projects-fa-umbrella", - "rule": ".projects-fa-umbrella", - "hash": "55f6a65e425c5725e953e3a59cb50f49" - }, - "projects-fa-users": { - "name": "projects-fa-users", - "rule": ".projects-fa-users", - "hash": "bd449bd0dea0d29031dc8fddad7bb66b" - }, - "projects-facebook": { - "name": "projects-facebook", - "rule": ".projects-facebook", - "hash": "16581191e4ce9e0115d447b479c886cb" - }, - "projects-facility": { - "name": "projects-facility", - "rule": ".projects-facility", - "hash": "d8893f9d2b75ec047b6f3898a386055c" - }, - "projects-film": { - "name": "projects-film", - "rule": ".projects-film", - "hash": "57497050fa09ba1533d981a9c1550ba9" - }, - "projects-forked": { - "name": "projects-forked", - "rule": ".projects-forked", - "hash": "f575428e1079981840297bd444e51c43" - }, - "projects-games": { - "name": "projects-games", - "rule": ".projects-games", - "hash": "b802cff3e76051675b37165bd9702088" - }, - "projects-ghost": { - "name": "projects-ghost", - "rule": ".projects-ghost", - "hash": "7c8622cad29bddc5179f6a6d5f15fbe9" - }, - "projects-gift": { - "name": "projects-gift", - "rule": ".projects-gift", - "hash": "f2ca678906a6806f421b60abddaa6cae" - }, - "projects-globe": { - "name": "projects-globe", - "rule": ".projects-globe", - "hash": "87515a83cc0c840804aca594677d1eae" - }, - "projects-golf": { - "name": "projects-golf", - "rule": ".projects-golf", - "hash": "1ee7556fab3d46d925deb00322dad858" - }, - "projects-heart": { - "name": "projects-heart", - "rule": ".projects-heart", - "hash": "3da64839e37ee245333017d0a310cc2e" - }, - "projects-intergalactic": { - "name": "projects-intergalactic", - "rule": ".projects-intergalactic", - "hash": "94dca756cb267bdb4e0ed58467320780" - }, - "projects-lock": { - "name": "projects-lock", - "rule": ".projects-lock", - "hash": "9d4c8ad3a4ac4163f284461da7df2763" - }, - "projects-mail": { - "name": "projects-mail", - "rule": ".projects-mail", - "hash": "963f5ce26c6caf86e72d754f7b6e8865" - }, - "projects-martini": { - "name": "projects-martini", - "rule": ".projects-martini", - "hash": "24d4d5fb5c334621ece4c35a9196471e" - }, - "projects-medical": { - "name": "projects-medical", - "rule": ".projects-medical", - "hash": "e0cb3ef5557321d166e8eb49c10d3599" - }, - "projects-mobile": { - "name": "projects-mobile", - "rule": ".projects-mobile", - "hash": "37dec95d1a4a937743d52acac319c3b6" - }, - "projects-music": { - "name": "projects-music", - "rule": ".projects-music", - "hash": "e7a814194685ac25be0db05b04074607" - }, - "projects-news": { - "name": "projects-news", - "rule": ".projects-news", - "hash": "6861f3ee827d09b0592166514f4941e8" - }, - "projects-orgchart": { - "name": "projects-orgchart", - "rule": ".projects-orgchart", - "hash": "20c51c59788fb2bc8184fdd5687d33dc" - }, - "projects-peoples": { - "name": "projects-peoples", - "rule": ".projects-peoples", - "hash": "c949ba6d09e68317a9a11482e75e5140" - }, - "projects-piechart": { - "name": "projects-piechart", - "rule": ".projects-piechart", - "hash": "051138560e30982a029aa5e4ea87bc17" - }, - "projects-poison": { - "name": "projects-poison", - "rule": ".projects-poison", - "hash": "56ddafd138e421f198b9cb38e5dc7455" - }, - "projects-putabirdonit": { - "name": "projects-putabirdonit", - "rule": ".projects-putabirdonit", - "hash": "ee298fff82c34341b986a3e1b77bea11" - }, - "projects-radiate": { - "name": "projects-radiate", - "rule": ".projects-radiate", - "hash": "9cfb918089b3de8506a5d270a119052c" - }, - "projects-savings": { - "name": "projects-savings", - "rule": ".projects-savings", - "hash": "9e92bc5e64f79d2f4842ac24a8b57fcb" - }, - "projects-search": { - "name": "projects-search", - "rule": ".projects-search", - "hash": "a42c1c31f2929838b0f181f417c0b6a4" - }, - "projects-shield": { - "name": "projects-shield", - "rule": ".projects-shield", - "hash": "40c6e1bec7c07c165668ac45c218847a" - }, - "projects-speed": { - "name": "projects-speed", - "rule": ".projects-speed", - "hash": "2b70c194d07f5a9d95abc51d84fb22ed" - }, - "projects-sprint": { - "name": "projects-sprint", - "rule": ".projects-sprint", - "hash": "655ef9a3043eab23eac1da21baeb36b3" - }, - "projects-star": { - "name": "projects-star", - "rule": ".projects-star", - "hash": "a46e3c18f68bc13a65b410496e27b5d7" - }, - "projects-storage": { - "name": "projects-storage", - "rule": ".projects-storage", - "hash": "bb19baa77bb7596f43f77e5dbbddb006" - }, - "projects-tablet": { - "name": "projects-tablet", - "rule": ".projects-tablet", - "hash": "830dcf6637288ca122c8f5034cae3769" - }, - "projects-travel": { - "name": "projects-travel", - "rule": ".projects-travel", - "hash": "86ec4dcd025879a43435b101fd542a1b" - }, - "projects-twitter": { - "name": "projects-twitter", - "rule": ".projects-twitter", - "hash": "75b8680dd1e4ecce4ca3a39c87e1ed80" - }, - "projects-warning": { - "name": "projects-warning", - "rule": ".projects-warning", - "hash": "3ac48b6f963675e1f4bb4ac75aad936f" - }, - "projects-whale": { - "name": "projects-whale", - "rule": ".projects-whale", - "hash": "569b584c7e80a0a9b965280abd27c723" - } - }, - "scales": [ - 1, - 2 - ], - "header": "\/**\n * @provides sprite-projects-css\n * @generated\n *\/\n\n.sprite-projects {\n background-image: url(\/rsrc\/image\/sprite-projects.png);\n background-repeat: no-repeat;\n}\n\n@media\nonly screen and (min-device-pixel-ratio: 1.5),\nonly screen and (-webkit-min-device-pixel-ratio: 1.5),\nonly screen and (min-resolution: 1.5dppx) {\n .sprite-projects {\n background-image: url(\/rsrc\/image\/sprite-projects-X2.png);\n background-size: {X}px {Y}px;\n }\n}\n", - "type": "standard" -} diff --git a/resources/sprite/projects_1x/8ball.png b/resources/sprite/projects_1x/8ball.png deleted file mode 100644 index 34f3a001b4..0000000000 Binary files a/resources/sprite/projects_1x/8ball.png and /dev/null differ diff --git a/resources/sprite/projects_1x/alien.png b/resources/sprite/projects_1x/alien.png deleted file mode 100644 index 4c8737432e..0000000000 Binary files a/resources/sprite/projects_1x/alien.png and /dev/null differ diff --git a/resources/sprite/projects_1x/announce.png b/resources/sprite/projects_1x/announce.png deleted file mode 100644 index 4d1bb5d7fb..0000000000 Binary files a/resources/sprite/projects_1x/announce.png and /dev/null differ diff --git a/resources/sprite/projects_1x/art.png b/resources/sprite/projects_1x/art.png deleted file mode 100644 index 3fbaeae7c3..0000000000 Binary files a/resources/sprite/projects_1x/art.png and /dev/null differ diff --git a/resources/sprite/projects_1x/award.png b/resources/sprite/projects_1x/award.png deleted file mode 100644 index 9ff2dddef3..0000000000 Binary files a/resources/sprite/projects_1x/award.png and /dev/null differ diff --git a/resources/sprite/projects_1x/bacon.png b/resources/sprite/projects_1x/bacon.png deleted file mode 100644 index 1cdf3abd7d..0000000000 Binary files a/resources/sprite/projects_1x/bacon.png and /dev/null differ diff --git a/resources/sprite/projects_1x/bandaid.png b/resources/sprite/projects_1x/bandaid.png deleted file mode 100644 index 65dfb34fe8..0000000000 Binary files a/resources/sprite/projects_1x/bandaid.png and /dev/null differ diff --git a/resources/sprite/projects_1x/beer.png b/resources/sprite/projects_1x/beer.png deleted file mode 100644 index 6a2892a4ed..0000000000 Binary files a/resources/sprite/projects_1x/beer.png and /dev/null differ diff --git a/resources/sprite/projects_1x/bomb.png b/resources/sprite/projects_1x/bomb.png deleted file mode 100644 index 85304e40c5..0000000000 Binary files a/resources/sprite/projects_1x/bomb.png and /dev/null differ diff --git a/resources/sprite/projects_1x/briefcase.png b/resources/sprite/projects_1x/briefcase.png deleted file mode 100644 index d6c6f5fb70..0000000000 Binary files a/resources/sprite/projects_1x/briefcase.png and /dev/null differ diff --git a/resources/sprite/projects_1x/bug.png b/resources/sprite/projects_1x/bug.png deleted file mode 100644 index 1dfb820150..0000000000 Binary files a/resources/sprite/projects_1x/bug.png and /dev/null differ diff --git a/resources/sprite/projects_1x/calendar.png b/resources/sprite/projects_1x/calendar.png deleted file mode 100644 index f4b39dd603..0000000000 Binary files a/resources/sprite/projects_1x/calendar.png and /dev/null differ diff --git a/resources/sprite/projects_1x/cloud.png b/resources/sprite/projects_1x/cloud.png deleted file mode 100644 index c1d4039f17..0000000000 Binary files a/resources/sprite/projects_1x/cloud.png and /dev/null differ diff --git a/resources/sprite/projects_1x/coffee.png b/resources/sprite/projects_1x/coffee.png deleted file mode 100644 index 511301bf9a..0000000000 Binary files a/resources/sprite/projects_1x/coffee.png and /dev/null differ diff --git a/resources/sprite/projects_1x/creditcard.png b/resources/sprite/projects_1x/creditcard.png deleted file mode 100644 index f96103d220..0000000000 Binary files a/resources/sprite/projects_1x/creditcard.png and /dev/null differ diff --git a/resources/sprite/projects_1x/death.png b/resources/sprite/projects_1x/death.png deleted file mode 100644 index 54fb486ee9..0000000000 Binary files a/resources/sprite/projects_1x/death.png and /dev/null differ diff --git a/resources/sprite/projects_1x/desktop.png b/resources/sprite/projects_1x/desktop.png deleted file mode 100644 index 2fb4be72f9..0000000000 Binary files a/resources/sprite/projects_1x/desktop.png and /dev/null differ diff --git a/resources/sprite/projects_1x/dropbox.png b/resources/sprite/projects_1x/dropbox.png deleted file mode 100644 index e18aaf10e6..0000000000 Binary files a/resources/sprite/projects_1x/dropbox.png and /dev/null differ diff --git a/resources/sprite/projects_1x/education.png b/resources/sprite/projects_1x/education.png deleted file mode 100644 index 3d75543949..0000000000 Binary files a/resources/sprite/projects_1x/education.png and /dev/null differ diff --git a/resources/sprite/projects_1x/experimental.png b/resources/sprite/projects_1x/experimental.png deleted file mode 100644 index 2b4e6d4fd1..0000000000 Binary files a/resources/sprite/projects_1x/experimental.png and /dev/null differ diff --git a/resources/sprite/projects_1x/fa-briefcase.png b/resources/sprite/projects_1x/fa-briefcase.png deleted file mode 100644 index 060a0fdec1..0000000000 Binary files a/resources/sprite/projects_1x/fa-briefcase.png and /dev/null differ diff --git a/resources/sprite/projects_1x/fa-bug.png b/resources/sprite/projects_1x/fa-bug.png deleted file mode 100644 index 532093e510..0000000000 Binary files a/resources/sprite/projects_1x/fa-bug.png and /dev/null differ diff --git a/resources/sprite/projects_1x/fa-building.png b/resources/sprite/projects_1x/fa-building.png deleted file mode 100644 index 1d3c2de98b..0000000000 Binary files a/resources/sprite/projects_1x/fa-building.png and /dev/null differ diff --git a/resources/sprite/projects_1x/fa-calendar.png b/resources/sprite/projects_1x/fa-calendar.png deleted file mode 100644 index 7568cac8fe..0000000000 Binary files a/resources/sprite/projects_1x/fa-calendar.png and /dev/null differ diff --git a/resources/sprite/projects_1x/fa-cloud.png b/resources/sprite/projects_1x/fa-cloud.png deleted file mode 100644 index f69ab9fbfc..0000000000 Binary files a/resources/sprite/projects_1x/fa-cloud.png and /dev/null differ diff --git a/resources/sprite/projects_1x/fa-credit-card.png b/resources/sprite/projects_1x/fa-credit-card.png deleted file mode 100644 index eb082d0f82..0000000000 Binary files a/resources/sprite/projects_1x/fa-credit-card.png and /dev/null differ diff --git a/resources/sprite/projects_1x/fa-envelope.png b/resources/sprite/projects_1x/fa-envelope.png deleted file mode 100644 index 4b744d358f..0000000000 Binary files a/resources/sprite/projects_1x/fa-envelope.png and /dev/null differ diff --git a/resources/sprite/projects_1x/fa-flag-checkered.png b/resources/sprite/projects_1x/fa-flag-checkered.png deleted file mode 100644 index c678e1ee59..0000000000 Binary files a/resources/sprite/projects_1x/fa-flag-checkered.png and /dev/null differ diff --git a/resources/sprite/projects_1x/fa-flask.png b/resources/sprite/projects_1x/fa-flask.png deleted file mode 100644 index fc59267342..0000000000 Binary files a/resources/sprite/projects_1x/fa-flask.png and /dev/null differ diff --git a/resources/sprite/projects_1x/fa-folder.png b/resources/sprite/projects_1x/fa-folder.png deleted file mode 100644 index 42babc267e..0000000000 Binary files a/resources/sprite/projects_1x/fa-folder.png and /dev/null differ diff --git a/resources/sprite/projects_1x/fa-lock.png b/resources/sprite/projects_1x/fa-lock.png deleted file mode 100644 index b87caf3aa0..0000000000 Binary files a/resources/sprite/projects_1x/fa-lock.png and /dev/null differ diff --git a/resources/sprite/projects_1x/fa-tags.png b/resources/sprite/projects_1x/fa-tags.png deleted file mode 100644 index eb2bbe4963..0000000000 Binary files a/resources/sprite/projects_1x/fa-tags.png and /dev/null differ diff --git a/resources/sprite/projects_1x/fa-trash-o.png b/resources/sprite/projects_1x/fa-trash-o.png deleted file mode 100644 index 89fa0daab4..0000000000 Binary files a/resources/sprite/projects_1x/fa-trash-o.png and /dev/null differ diff --git a/resources/sprite/projects_1x/fa-truck.png b/resources/sprite/projects_1x/fa-truck.png deleted file mode 100644 index 13e8a96b69..0000000000 Binary files a/resources/sprite/projects_1x/fa-truck.png and /dev/null differ diff --git a/resources/sprite/projects_1x/fa-umbrella.png b/resources/sprite/projects_1x/fa-umbrella.png deleted file mode 100644 index 7faad81e6d..0000000000 Binary files a/resources/sprite/projects_1x/fa-umbrella.png and /dev/null differ diff --git a/resources/sprite/projects_1x/fa-users.png b/resources/sprite/projects_1x/fa-users.png deleted file mode 100644 index cbd5cf545d..0000000000 Binary files a/resources/sprite/projects_1x/fa-users.png and /dev/null differ diff --git a/resources/sprite/projects_1x/facebook.png b/resources/sprite/projects_1x/facebook.png deleted file mode 100644 index 029c12eed9..0000000000 Binary files a/resources/sprite/projects_1x/facebook.png and /dev/null differ diff --git a/resources/sprite/projects_1x/facility.png b/resources/sprite/projects_1x/facility.png deleted file mode 100644 index 044e9a106b..0000000000 Binary files a/resources/sprite/projects_1x/facility.png and /dev/null differ diff --git a/resources/sprite/projects_1x/film.png b/resources/sprite/projects_1x/film.png deleted file mode 100644 index b2a44962dd..0000000000 Binary files a/resources/sprite/projects_1x/film.png and /dev/null differ diff --git a/resources/sprite/projects_1x/forked.png b/resources/sprite/projects_1x/forked.png deleted file mode 100644 index 28d898e8e6..0000000000 Binary files a/resources/sprite/projects_1x/forked.png and /dev/null differ diff --git a/resources/sprite/projects_1x/games.png b/resources/sprite/projects_1x/games.png deleted file mode 100644 index 5f3e6fce3f..0000000000 Binary files a/resources/sprite/projects_1x/games.png and /dev/null differ diff --git a/resources/sprite/projects_1x/ghost.png b/resources/sprite/projects_1x/ghost.png deleted file mode 100644 index af601a7542..0000000000 Binary files a/resources/sprite/projects_1x/ghost.png and /dev/null differ diff --git a/resources/sprite/projects_1x/gift.png b/resources/sprite/projects_1x/gift.png deleted file mode 100644 index d611c181f3..0000000000 Binary files a/resources/sprite/projects_1x/gift.png and /dev/null differ diff --git a/resources/sprite/projects_1x/globe.png b/resources/sprite/projects_1x/globe.png deleted file mode 100644 index f78741bb05..0000000000 Binary files a/resources/sprite/projects_1x/globe.png and /dev/null differ diff --git a/resources/sprite/projects_1x/golf.png b/resources/sprite/projects_1x/golf.png deleted file mode 100644 index 0a7cf98cb4..0000000000 Binary files a/resources/sprite/projects_1x/golf.png and /dev/null differ diff --git a/resources/sprite/projects_1x/heart.png b/resources/sprite/projects_1x/heart.png deleted file mode 100644 index bfd83aa1f4..0000000000 Binary files a/resources/sprite/projects_1x/heart.png and /dev/null differ diff --git a/resources/sprite/projects_1x/intergalactic.png b/resources/sprite/projects_1x/intergalactic.png deleted file mode 100644 index 5d0053b678..0000000000 Binary files a/resources/sprite/projects_1x/intergalactic.png and /dev/null differ diff --git a/resources/sprite/projects_1x/lock.png b/resources/sprite/projects_1x/lock.png deleted file mode 100644 index fdb14fe429..0000000000 Binary files a/resources/sprite/projects_1x/lock.png and /dev/null differ diff --git a/resources/sprite/projects_1x/mail.png b/resources/sprite/projects_1x/mail.png deleted file mode 100644 index d10d0098aa..0000000000 Binary files a/resources/sprite/projects_1x/mail.png and /dev/null differ diff --git a/resources/sprite/projects_1x/martini.png b/resources/sprite/projects_1x/martini.png deleted file mode 100644 index 9fe5b144c1..0000000000 Binary files a/resources/sprite/projects_1x/martini.png and /dev/null differ diff --git a/resources/sprite/projects_1x/medical.png b/resources/sprite/projects_1x/medical.png deleted file mode 100644 index 6e4e6c3f99..0000000000 Binary files a/resources/sprite/projects_1x/medical.png and /dev/null differ diff --git a/resources/sprite/projects_1x/mobile.png b/resources/sprite/projects_1x/mobile.png deleted file mode 100644 index 73799da561..0000000000 Binary files a/resources/sprite/projects_1x/mobile.png and /dev/null differ diff --git a/resources/sprite/projects_1x/music.png b/resources/sprite/projects_1x/music.png deleted file mode 100644 index daf0d3e1f7..0000000000 Binary files a/resources/sprite/projects_1x/music.png and /dev/null differ diff --git a/resources/sprite/projects_1x/news.png b/resources/sprite/projects_1x/news.png deleted file mode 100644 index d50cf67aac..0000000000 Binary files a/resources/sprite/projects_1x/news.png and /dev/null differ diff --git a/resources/sprite/projects_1x/orgchart.png b/resources/sprite/projects_1x/orgchart.png deleted file mode 100644 index cb9e799290..0000000000 Binary files a/resources/sprite/projects_1x/orgchart.png and /dev/null differ diff --git a/resources/sprite/projects_1x/peoples.png b/resources/sprite/projects_1x/peoples.png deleted file mode 100644 index 8968e86453..0000000000 Binary files a/resources/sprite/projects_1x/peoples.png and /dev/null differ diff --git a/resources/sprite/projects_1x/piechart.png b/resources/sprite/projects_1x/piechart.png deleted file mode 100644 index ac74091bf9..0000000000 Binary files a/resources/sprite/projects_1x/piechart.png and /dev/null differ diff --git a/resources/sprite/projects_1x/poison.png b/resources/sprite/projects_1x/poison.png deleted file mode 100644 index 4ed9b21006..0000000000 Binary files a/resources/sprite/projects_1x/poison.png and /dev/null differ diff --git a/resources/sprite/projects_1x/putabirdonit.png b/resources/sprite/projects_1x/putabirdonit.png deleted file mode 100644 index 68b7e3ae91..0000000000 Binary files a/resources/sprite/projects_1x/putabirdonit.png and /dev/null differ diff --git a/resources/sprite/projects_1x/radiate.png b/resources/sprite/projects_1x/radiate.png deleted file mode 100644 index 634707e1ab..0000000000 Binary files a/resources/sprite/projects_1x/radiate.png and /dev/null differ diff --git a/resources/sprite/projects_1x/savings.png b/resources/sprite/projects_1x/savings.png deleted file mode 100644 index 39ffc216a1..0000000000 Binary files a/resources/sprite/projects_1x/savings.png and /dev/null differ diff --git a/resources/sprite/projects_1x/search.png b/resources/sprite/projects_1x/search.png deleted file mode 100644 index 85018f5c65..0000000000 Binary files a/resources/sprite/projects_1x/search.png and /dev/null differ diff --git a/resources/sprite/projects_1x/shield.png b/resources/sprite/projects_1x/shield.png deleted file mode 100644 index 78a6e7494e..0000000000 Binary files a/resources/sprite/projects_1x/shield.png and /dev/null differ diff --git a/resources/sprite/projects_1x/speed.png b/resources/sprite/projects_1x/speed.png deleted file mode 100644 index 8f2c943083..0000000000 Binary files a/resources/sprite/projects_1x/speed.png and /dev/null differ diff --git a/resources/sprite/projects_1x/sprint.png b/resources/sprite/projects_1x/sprint.png deleted file mode 100644 index 1e6acc7399..0000000000 Binary files a/resources/sprite/projects_1x/sprint.png and /dev/null differ diff --git a/resources/sprite/projects_1x/star.png b/resources/sprite/projects_1x/star.png deleted file mode 100644 index e0ad9d39c6..0000000000 Binary files a/resources/sprite/projects_1x/star.png and /dev/null differ diff --git a/resources/sprite/projects_1x/storage.png b/resources/sprite/projects_1x/storage.png deleted file mode 100644 index ede9d46c5a..0000000000 Binary files a/resources/sprite/projects_1x/storage.png and /dev/null differ diff --git a/resources/sprite/projects_1x/tablet.png b/resources/sprite/projects_1x/tablet.png deleted file mode 100644 index 6121f4dc9a..0000000000 Binary files a/resources/sprite/projects_1x/tablet.png and /dev/null differ diff --git a/resources/sprite/projects_1x/travel.png b/resources/sprite/projects_1x/travel.png deleted file mode 100644 index 3f3b995747..0000000000 Binary files a/resources/sprite/projects_1x/travel.png and /dev/null differ diff --git a/resources/sprite/projects_1x/twitter.png b/resources/sprite/projects_1x/twitter.png deleted file mode 100644 index 808db17ebf..0000000000 Binary files a/resources/sprite/projects_1x/twitter.png and /dev/null differ diff --git a/resources/sprite/projects_1x/warning.png b/resources/sprite/projects_1x/warning.png deleted file mode 100644 index 18757ecc5c..0000000000 Binary files a/resources/sprite/projects_1x/warning.png and /dev/null differ diff --git a/resources/sprite/projects_1x/whale.png b/resources/sprite/projects_1x/whale.png deleted file mode 100644 index df2039235a..0000000000 Binary files a/resources/sprite/projects_1x/whale.png and /dev/null differ diff --git a/resources/sprite/projects_2x/8ball.png b/resources/sprite/projects_2x/8ball.png deleted file mode 100644 index 8a40ad6c3a..0000000000 Binary files a/resources/sprite/projects_2x/8ball.png and /dev/null differ diff --git a/resources/sprite/projects_2x/alien.png b/resources/sprite/projects_2x/alien.png deleted file mode 100644 index 7956705045..0000000000 Binary files a/resources/sprite/projects_2x/alien.png and /dev/null differ diff --git a/resources/sprite/projects_2x/announce.png b/resources/sprite/projects_2x/announce.png deleted file mode 100644 index d39630e9f9..0000000000 Binary files a/resources/sprite/projects_2x/announce.png and /dev/null differ diff --git a/resources/sprite/projects_2x/art.png b/resources/sprite/projects_2x/art.png deleted file mode 100644 index c6450ed9bc..0000000000 Binary files a/resources/sprite/projects_2x/art.png and /dev/null differ diff --git a/resources/sprite/projects_2x/award.png b/resources/sprite/projects_2x/award.png deleted file mode 100644 index 924067dfff..0000000000 Binary files a/resources/sprite/projects_2x/award.png and /dev/null differ diff --git a/resources/sprite/projects_2x/bacon.png b/resources/sprite/projects_2x/bacon.png deleted file mode 100644 index 0d413181d5..0000000000 Binary files a/resources/sprite/projects_2x/bacon.png and /dev/null differ diff --git a/resources/sprite/projects_2x/bandaid.png b/resources/sprite/projects_2x/bandaid.png deleted file mode 100644 index 5526da1c9a..0000000000 Binary files a/resources/sprite/projects_2x/bandaid.png and /dev/null differ diff --git a/resources/sprite/projects_2x/beer.png b/resources/sprite/projects_2x/beer.png deleted file mode 100644 index e51c3bbc59..0000000000 Binary files a/resources/sprite/projects_2x/beer.png and /dev/null differ diff --git a/resources/sprite/projects_2x/bomb.png b/resources/sprite/projects_2x/bomb.png deleted file mode 100644 index 4b259fcb88..0000000000 Binary files a/resources/sprite/projects_2x/bomb.png and /dev/null differ diff --git a/resources/sprite/projects_2x/briefcase.png b/resources/sprite/projects_2x/briefcase.png deleted file mode 100644 index e3e953ec16..0000000000 Binary files a/resources/sprite/projects_2x/briefcase.png and /dev/null differ diff --git a/resources/sprite/projects_2x/bug.png b/resources/sprite/projects_2x/bug.png deleted file mode 100644 index 4f177e434a..0000000000 Binary files a/resources/sprite/projects_2x/bug.png and /dev/null differ diff --git a/resources/sprite/projects_2x/calendar.png b/resources/sprite/projects_2x/calendar.png deleted file mode 100644 index 6093a14638..0000000000 Binary files a/resources/sprite/projects_2x/calendar.png and /dev/null differ diff --git a/resources/sprite/projects_2x/cloud.png b/resources/sprite/projects_2x/cloud.png deleted file mode 100644 index f02dc156f1..0000000000 Binary files a/resources/sprite/projects_2x/cloud.png and /dev/null differ diff --git a/resources/sprite/projects_2x/coffee.png b/resources/sprite/projects_2x/coffee.png deleted file mode 100644 index f3ad8bcf3c..0000000000 Binary files a/resources/sprite/projects_2x/coffee.png and /dev/null differ diff --git a/resources/sprite/projects_2x/creditcard.png b/resources/sprite/projects_2x/creditcard.png deleted file mode 100644 index b5c7347030..0000000000 Binary files a/resources/sprite/projects_2x/creditcard.png and /dev/null differ diff --git a/resources/sprite/projects_2x/death.png b/resources/sprite/projects_2x/death.png deleted file mode 100644 index a588d306f6..0000000000 Binary files a/resources/sprite/projects_2x/death.png and /dev/null differ diff --git a/resources/sprite/projects_2x/desktop.png b/resources/sprite/projects_2x/desktop.png deleted file mode 100644 index b9715f03b5..0000000000 Binary files a/resources/sprite/projects_2x/desktop.png and /dev/null differ diff --git a/resources/sprite/projects_2x/dropbox.png b/resources/sprite/projects_2x/dropbox.png deleted file mode 100644 index 49dc0a2480..0000000000 Binary files a/resources/sprite/projects_2x/dropbox.png and /dev/null differ diff --git a/resources/sprite/projects_2x/education.png b/resources/sprite/projects_2x/education.png deleted file mode 100644 index e1675d89a3..0000000000 Binary files a/resources/sprite/projects_2x/education.png and /dev/null differ diff --git a/resources/sprite/projects_2x/experimental.png b/resources/sprite/projects_2x/experimental.png deleted file mode 100644 index 3a10b8ede4..0000000000 Binary files a/resources/sprite/projects_2x/experimental.png and /dev/null differ diff --git a/resources/sprite/projects_2x/fa-briefcase.png b/resources/sprite/projects_2x/fa-briefcase.png deleted file mode 100644 index 2923f59af9..0000000000 Binary files a/resources/sprite/projects_2x/fa-briefcase.png and /dev/null differ diff --git a/resources/sprite/projects_2x/fa-bug.png b/resources/sprite/projects_2x/fa-bug.png deleted file mode 100644 index 6494e0a204..0000000000 Binary files a/resources/sprite/projects_2x/fa-bug.png and /dev/null differ diff --git a/resources/sprite/projects_2x/fa-building.png b/resources/sprite/projects_2x/fa-building.png deleted file mode 100644 index 95e7b14ff6..0000000000 Binary files a/resources/sprite/projects_2x/fa-building.png and /dev/null differ diff --git a/resources/sprite/projects_2x/fa-calendar.png b/resources/sprite/projects_2x/fa-calendar.png deleted file mode 100644 index fd507229d1..0000000000 Binary files a/resources/sprite/projects_2x/fa-calendar.png and /dev/null differ diff --git a/resources/sprite/projects_2x/fa-cloud.png b/resources/sprite/projects_2x/fa-cloud.png deleted file mode 100644 index 18c343d278..0000000000 Binary files a/resources/sprite/projects_2x/fa-cloud.png and /dev/null differ diff --git a/resources/sprite/projects_2x/fa-credit-card.png b/resources/sprite/projects_2x/fa-credit-card.png deleted file mode 100644 index bc67b7a408..0000000000 Binary files a/resources/sprite/projects_2x/fa-credit-card.png and /dev/null differ diff --git a/resources/sprite/projects_2x/fa-envelope.png b/resources/sprite/projects_2x/fa-envelope.png deleted file mode 100644 index 40be12279a..0000000000 Binary files a/resources/sprite/projects_2x/fa-envelope.png and /dev/null differ diff --git a/resources/sprite/projects_2x/fa-flag-checkered.png b/resources/sprite/projects_2x/fa-flag-checkered.png deleted file mode 100644 index a17503a2d2..0000000000 Binary files a/resources/sprite/projects_2x/fa-flag-checkered.png and /dev/null differ diff --git a/resources/sprite/projects_2x/fa-flask.png b/resources/sprite/projects_2x/fa-flask.png deleted file mode 100644 index 5703f5e812..0000000000 Binary files a/resources/sprite/projects_2x/fa-flask.png and /dev/null differ diff --git a/resources/sprite/projects_2x/fa-folder.png b/resources/sprite/projects_2x/fa-folder.png deleted file mode 100644 index d2fb95f9b0..0000000000 Binary files a/resources/sprite/projects_2x/fa-folder.png and /dev/null differ diff --git a/resources/sprite/projects_2x/fa-lock.png b/resources/sprite/projects_2x/fa-lock.png deleted file mode 100644 index 1033fc72ae..0000000000 Binary files a/resources/sprite/projects_2x/fa-lock.png and /dev/null differ diff --git a/resources/sprite/projects_2x/fa-tags.png b/resources/sprite/projects_2x/fa-tags.png deleted file mode 100644 index ede45665e1..0000000000 Binary files a/resources/sprite/projects_2x/fa-tags.png and /dev/null differ diff --git a/resources/sprite/projects_2x/fa-trash-o.png b/resources/sprite/projects_2x/fa-trash-o.png deleted file mode 100644 index 909c1e4135..0000000000 Binary files a/resources/sprite/projects_2x/fa-trash-o.png and /dev/null differ diff --git a/resources/sprite/projects_2x/fa-truck.png b/resources/sprite/projects_2x/fa-truck.png deleted file mode 100644 index 2a0333c3ae..0000000000 Binary files a/resources/sprite/projects_2x/fa-truck.png and /dev/null differ diff --git a/resources/sprite/projects_2x/fa-umbrella.png b/resources/sprite/projects_2x/fa-umbrella.png deleted file mode 100644 index 648e86c665..0000000000 Binary files a/resources/sprite/projects_2x/fa-umbrella.png and /dev/null differ diff --git a/resources/sprite/projects_2x/fa-users.png b/resources/sprite/projects_2x/fa-users.png deleted file mode 100644 index f0970d65a2..0000000000 Binary files a/resources/sprite/projects_2x/fa-users.png and /dev/null differ diff --git a/resources/sprite/projects_2x/facebook.png b/resources/sprite/projects_2x/facebook.png deleted file mode 100644 index 2acd42067c..0000000000 Binary files a/resources/sprite/projects_2x/facebook.png and /dev/null differ diff --git a/resources/sprite/projects_2x/facility.png b/resources/sprite/projects_2x/facility.png deleted file mode 100644 index f6594eda4f..0000000000 Binary files a/resources/sprite/projects_2x/facility.png and /dev/null differ diff --git a/resources/sprite/projects_2x/film.png b/resources/sprite/projects_2x/film.png deleted file mode 100644 index 0050116a53..0000000000 Binary files a/resources/sprite/projects_2x/film.png and /dev/null differ diff --git a/resources/sprite/projects_2x/forked.png b/resources/sprite/projects_2x/forked.png deleted file mode 100644 index 32f4c549b3..0000000000 Binary files a/resources/sprite/projects_2x/forked.png and /dev/null differ diff --git a/resources/sprite/projects_2x/games.png b/resources/sprite/projects_2x/games.png deleted file mode 100644 index 7b67835b4a..0000000000 Binary files a/resources/sprite/projects_2x/games.png and /dev/null differ diff --git a/resources/sprite/projects_2x/ghost.png b/resources/sprite/projects_2x/ghost.png deleted file mode 100644 index 796acb51fa..0000000000 Binary files a/resources/sprite/projects_2x/ghost.png and /dev/null differ diff --git a/resources/sprite/projects_2x/gift.png b/resources/sprite/projects_2x/gift.png deleted file mode 100644 index e0324f081d..0000000000 Binary files a/resources/sprite/projects_2x/gift.png and /dev/null differ diff --git a/resources/sprite/projects_2x/globe.png b/resources/sprite/projects_2x/globe.png deleted file mode 100644 index 9fc691e165..0000000000 Binary files a/resources/sprite/projects_2x/globe.png and /dev/null differ diff --git a/resources/sprite/projects_2x/golf.png b/resources/sprite/projects_2x/golf.png deleted file mode 100644 index 6052476460..0000000000 Binary files a/resources/sprite/projects_2x/golf.png and /dev/null differ diff --git a/resources/sprite/projects_2x/heart.png b/resources/sprite/projects_2x/heart.png deleted file mode 100644 index d92dd454d7..0000000000 Binary files a/resources/sprite/projects_2x/heart.png and /dev/null differ diff --git a/resources/sprite/projects_2x/intergalactic.png b/resources/sprite/projects_2x/intergalactic.png deleted file mode 100644 index 03e1565fb9..0000000000 Binary files a/resources/sprite/projects_2x/intergalactic.png and /dev/null differ diff --git a/resources/sprite/projects_2x/lock.png b/resources/sprite/projects_2x/lock.png deleted file mode 100644 index 23eb42d8b6..0000000000 Binary files a/resources/sprite/projects_2x/lock.png and /dev/null differ diff --git a/resources/sprite/projects_2x/mail.png b/resources/sprite/projects_2x/mail.png deleted file mode 100644 index 3a7f87a72b..0000000000 Binary files a/resources/sprite/projects_2x/mail.png and /dev/null differ diff --git a/resources/sprite/projects_2x/martini.png b/resources/sprite/projects_2x/martini.png deleted file mode 100644 index ba90423952..0000000000 Binary files a/resources/sprite/projects_2x/martini.png and /dev/null differ diff --git a/resources/sprite/projects_2x/medical.png b/resources/sprite/projects_2x/medical.png deleted file mode 100644 index aec84f070b..0000000000 Binary files a/resources/sprite/projects_2x/medical.png and /dev/null differ diff --git a/resources/sprite/projects_2x/mobile.png b/resources/sprite/projects_2x/mobile.png deleted file mode 100644 index 68bb17cc1b..0000000000 Binary files a/resources/sprite/projects_2x/mobile.png and /dev/null differ diff --git a/resources/sprite/projects_2x/music.png b/resources/sprite/projects_2x/music.png deleted file mode 100644 index 2f6da31763..0000000000 Binary files a/resources/sprite/projects_2x/music.png and /dev/null differ diff --git a/resources/sprite/projects_2x/news.png b/resources/sprite/projects_2x/news.png deleted file mode 100644 index 8285a7c02d..0000000000 Binary files a/resources/sprite/projects_2x/news.png and /dev/null differ diff --git a/resources/sprite/projects_2x/orgchart.png b/resources/sprite/projects_2x/orgchart.png deleted file mode 100644 index 89cbb84ec8..0000000000 Binary files a/resources/sprite/projects_2x/orgchart.png and /dev/null differ diff --git a/resources/sprite/projects_2x/peoples.png b/resources/sprite/projects_2x/peoples.png deleted file mode 100644 index fb366cb378..0000000000 Binary files a/resources/sprite/projects_2x/peoples.png and /dev/null differ diff --git a/resources/sprite/projects_2x/piechart.png b/resources/sprite/projects_2x/piechart.png deleted file mode 100644 index 2c403ed33e..0000000000 Binary files a/resources/sprite/projects_2x/piechart.png and /dev/null differ diff --git a/resources/sprite/projects_2x/poison.png b/resources/sprite/projects_2x/poison.png deleted file mode 100644 index e8fe492649..0000000000 Binary files a/resources/sprite/projects_2x/poison.png and /dev/null differ diff --git a/resources/sprite/projects_2x/putabirdonit.png b/resources/sprite/projects_2x/putabirdonit.png deleted file mode 100644 index 34f7de1a1c..0000000000 Binary files a/resources/sprite/projects_2x/putabirdonit.png and /dev/null differ diff --git a/resources/sprite/projects_2x/radiate.png b/resources/sprite/projects_2x/radiate.png deleted file mode 100644 index 2195a8f8f3..0000000000 Binary files a/resources/sprite/projects_2x/radiate.png and /dev/null differ diff --git a/resources/sprite/projects_2x/savings.png b/resources/sprite/projects_2x/savings.png deleted file mode 100644 index 8499c023a6..0000000000 Binary files a/resources/sprite/projects_2x/savings.png and /dev/null differ diff --git a/resources/sprite/projects_2x/search.png b/resources/sprite/projects_2x/search.png deleted file mode 100644 index 3b19629506..0000000000 Binary files a/resources/sprite/projects_2x/search.png and /dev/null differ diff --git a/resources/sprite/projects_2x/shield.png b/resources/sprite/projects_2x/shield.png deleted file mode 100644 index 73b96ae892..0000000000 Binary files a/resources/sprite/projects_2x/shield.png and /dev/null differ diff --git a/resources/sprite/projects_2x/speed.png b/resources/sprite/projects_2x/speed.png deleted file mode 100644 index b986e9fdd8..0000000000 Binary files a/resources/sprite/projects_2x/speed.png and /dev/null differ diff --git a/resources/sprite/projects_2x/sprint.png b/resources/sprite/projects_2x/sprint.png deleted file mode 100644 index feb29ef0fc..0000000000 Binary files a/resources/sprite/projects_2x/sprint.png and /dev/null differ diff --git a/resources/sprite/projects_2x/star.png b/resources/sprite/projects_2x/star.png deleted file mode 100644 index 35f8e802b9..0000000000 Binary files a/resources/sprite/projects_2x/star.png and /dev/null differ diff --git a/resources/sprite/projects_2x/storage.png b/resources/sprite/projects_2x/storage.png deleted file mode 100644 index b538161b0b..0000000000 Binary files a/resources/sprite/projects_2x/storage.png and /dev/null differ diff --git a/resources/sprite/projects_2x/tablet.png b/resources/sprite/projects_2x/tablet.png deleted file mode 100644 index ba08795dbd..0000000000 Binary files a/resources/sprite/projects_2x/tablet.png and /dev/null differ diff --git a/resources/sprite/projects_2x/travel.png b/resources/sprite/projects_2x/travel.png deleted file mode 100644 index 828f4d1860..0000000000 Binary files a/resources/sprite/projects_2x/travel.png and /dev/null differ diff --git a/resources/sprite/projects_2x/twitter.png b/resources/sprite/projects_2x/twitter.png deleted file mode 100644 index 620b437d86..0000000000 Binary files a/resources/sprite/projects_2x/twitter.png and /dev/null differ diff --git a/resources/sprite/projects_2x/warning.png b/resources/sprite/projects_2x/warning.png deleted file mode 100644 index f07e8a467b..0000000000 Binary files a/resources/sprite/projects_2x/warning.png and /dev/null differ diff --git a/resources/sprite/projects_2x/whale.png b/resources/sprite/projects_2x/whale.png deleted file mode 100644 index 986dfc298e..0000000000 Binary files a/resources/sprite/projects_2x/whale.png and /dev/null differ diff --git a/resources/sql/autopatches/20160119.project.1.silence.sql b/resources/sql/autopatches/20160119.project.1.silence.sql new file mode 100644 index 0000000000..3a4dd07fd2 --- /dev/null +++ b/resources/sql/autopatches/20160119.project.1.silence.sql @@ -0,0 +1,8 @@ +/* PhabricatorObjectHasUnsubscriberEdgeType::EDGECONST = 23 */ +/* PhabricatorProjectSilencedEdgeType::EDGECONST = 61 */ + +/* This is converting existing unsubscribes into disabled mail. */ + +INSERT IGNORE INTO {$NAMESPACE}_project.edge (src, type, dst, dateCreated) + SELECT src, 61, dst, dateCreated FROM {$NAMESPACE}_project.edge + WHERE type = 23; diff --git a/resources/sql/autopatches/20160122.project.1.boarddefault.php b/resources/sql/autopatches/20160122.project.1.boarddefault.php new file mode 100644 index 0000000000..8765184629 --- /dev/null +++ b/resources/sql/autopatches/20160122.project.1.boarddefault.php @@ -0,0 +1,60 @@ +establishConnection('w'); + +$panel_table = id(new PhabricatorProfilePanelConfiguration()); +$panel_conn = $panel_table->establishConnection('w'); + +foreach (new LiskMigrationIterator($project_table) as $project) { + $columns = queryfx_all( + $conn_w, + 'SELECT * FROM %T WHERE projectPHID = %s', + id(new PhabricatorProjectColumn())->getTableName(), + $project->getPHID()); + + // This project has no columns, so we don't need to change anything. + if (!$columns) { + continue; + } + + // This project has columns, so set its workboard flag. + queryfx( + $conn_w, + 'UPDATE %T SET hasWorkboard = 1 WHERE id = %d', + $project->getTableName(), + $project->getID()); + + // Try to set the default menu item to "Workboard". + $config = queryfx_all( + $panel_conn, + 'SELECT * FROM %T WHERE profilePHID = %s', + $panel_table->getTableName(), + $project->getPHID()); + + // There are already some settings, so don't touch them. + if ($config) { + continue; + } + + queryfx( + $panel_conn, + 'INSERT INTO %T + (phid, profilePHID, panelKey, builtinKey, visibility, panelProperties, + panelOrder, dateCreated, dateModified) + VALUES (%s, %s, %s, %s, %s, %s, %d, %d, %d)', + $panel_table->getTableName(), + $panel_table->generatePHID(), + $project->getPHID(), + PhabricatorProjectWorkboardProfilePanel::PANELKEY, + PhabricatorProject::PANEL_WORKBOARD, + PhabricatorProfilePanelConfiguration::VISIBILITY_DEFAULT, + '{}', + 2, + PhabricatorTime::getNow(), + PhabricatorTime::getNow()); +} diff --git a/resources/sql/quickstart.sql b/resources/sql/quickstart.sql index fdc1e673c7..1d1defd6de 100644 --- a/resources/sql/quickstart.sql +++ b/resources/sql/quickstart.sql @@ -342,10 +342,8 @@ CREATE TABLE `daemon_log` ( `explicitArgv` longtext COLLATE {$COLLATE_TEXT} NOT NULL, `dateCreated` int(10) unsigned NOT NULL, `dateModified` int(10) unsigned NOT NULL, - `envHash` binary(40) NOT NULL, `status` varchar(8) COLLATE {$COLLATE_TEXT} NOT NULL, `runningAsUser` varchar(255) COLLATE {$COLLATE_TEXT} DEFAULT NULL, - `envInfo` longtext COLLATE {$COLLATE_TEXT} NOT NULL, `daemonID` varchar(64) COLLATE {$COLLATE_TEXT} NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `key_daemonID` (`daemonID`), @@ -668,10 +666,38 @@ CREATE TABLE `draft` ( UNIQUE KEY `authorPHID` (`authorPHID`,`draftKey`) ) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE={$COLLATE_TEXT}; +CREATE TABLE `draft_versioneddraft` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `objectPHID` varbinary(64) NOT NULL, + `authorPHID` varbinary(64) NOT NULL, + `version` int(10) unsigned NOT NULL, + `properties` longtext COLLATE {$COLLATE_TEXT} NOT NULL, + `dateCreated` int(10) unsigned NOT NULL, + `dateModified` int(10) unsigned NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `key_object` (`objectPHID`,`authorPHID`,`version`) +) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE={$COLLATE_TEXT}; + CREATE DATABASE /*!32312 IF NOT EXISTS*/ `{$NAMESPACE}_drydock` /*!40100 DEFAULT CHARACTER SET {$CHARSET} COLLATE {$COLLATE_TEXT} */; USE `{$NAMESPACE}_drydock`; +CREATE TABLE `drydock_authorization` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `phid` varbinary(64) NOT NULL, + `blueprintPHID` varbinary(64) NOT NULL, + `blueprintAuthorizationState` varchar(32) COLLATE {$COLLATE_TEXT} NOT NULL, + `objectPHID` varbinary(64) NOT NULL, + `objectAuthorizationState` varchar(32) COLLATE {$COLLATE_TEXT} NOT NULL, + `dateCreated` int(10) unsigned NOT NULL, + `dateModified` int(10) unsigned NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `key_phid` (`phid`), + UNIQUE KEY `key_unique` (`objectPHID`,`blueprintPHID`), + KEY `key_blueprint` (`blueprintPHID`,`blueprintAuthorizationState`), + KEY `key_object` (`objectPHID`,`objectAuthorizationState`) +) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE={$COLLATE_TEXT}; + CREATE TABLE `drydock_blueprint` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `phid` varbinary(64) NOT NULL, @@ -731,6 +757,7 @@ CREATE TABLE `drydock_lease` ( `dateModified` int(10) unsigned NOT NULL, `resourceType` varchar(128) COLLATE {$COLLATE_TEXT} NOT NULL, `resourcePHID` varbinary(64) DEFAULT NULL, + `authorizingPHID` varbinary(64) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `key_phid` (`phid`), KEY `key_resource` (`resourcePHID`,`status`) @@ -738,20 +765,41 @@ CREATE TABLE `drydock_lease` ( CREATE TABLE `drydock_log` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `resourceID` int(10) unsigned DEFAULT NULL, - `leaseID` int(10) unsigned DEFAULT NULL, `epoch` int(10) unsigned NOT NULL, - `message` longtext COLLATE {$COLLATE_TEXT} NOT NULL, + `blueprintPHID` varbinary(64) DEFAULT NULL, + `resourcePHID` varbinary(64) DEFAULT NULL, + `leasePHID` varbinary(64) DEFAULT NULL, + `type` varchar(64) COLLATE {$COLLATE_TEXT} NOT NULL, + `data` longtext COLLATE {$COLLATE_TEXT} NOT NULL, PRIMARY KEY (`id`), - KEY `resourceID` (`resourceID`,`epoch`), - KEY `leaseID` (`leaseID`,`epoch`), - KEY `epoch` (`epoch`) + KEY `epoch` (`epoch`), + KEY `key_blueprint` (`blueprintPHID`,`type`), + KEY `key_resource` (`resourcePHID`,`type`), + KEY `key_lease` (`leasePHID`,`type`) +) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE={$COLLATE_TEXT}; + +CREATE TABLE `drydock_repositoryoperation` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `phid` varbinary(64) NOT NULL, + `authorPHID` varbinary(64) NOT NULL, + `objectPHID` varbinary(64) NOT NULL, + `repositoryPHID` varbinary(64) NOT NULL, + `repositoryTarget` longblob NOT NULL, + `operationType` varchar(32) COLLATE {$COLLATE_TEXT} NOT NULL, + `operationState` varchar(32) COLLATE {$COLLATE_TEXT} NOT NULL, + `properties` longtext COLLATE {$COLLATE_TEXT} NOT NULL, + `dateCreated` int(10) unsigned NOT NULL, + `dateModified` int(10) unsigned NOT NULL, + `isDismissed` tinyint(1) NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `key_phid` (`phid`), + KEY `key_object` (`objectPHID`), + KEY `key_repository` (`repositoryPHID`,`operationState`) ) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE={$COLLATE_TEXT}; CREATE TABLE `drydock_resource` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `phid` varbinary(64) NOT NULL, - `name` varchar(255) COLLATE {$COLLATE_TEXT} NOT NULL, `ownerPHID` varbinary(64) DEFAULT NULL, `status` varchar(32) COLLATE {$COLLATE_TEXT} NOT NULL, `type` varchar(64) COLLATE {$COLLATE_TEXT} NOT NULL, @@ -1044,6 +1092,8 @@ CREATE TABLE `harbormaster_build` ( `dateModified` int(10) unsigned NOT NULL, `buildGeneration` int(10) unsigned NOT NULL DEFAULT '0', `planAutoKey` varchar(32) COLLATE {$COLLATE_TEXT} DEFAULT NULL, + `buildParameters` longtext COLLATE {$COLLATE_TEXT} NOT NULL, + `initiatorPHID` varbinary(64) DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `key_phid` (`phid`), UNIQUE KEY `key_planautokey` (`buildablePHID`,`planAutoKey`), @@ -1177,6 +1227,8 @@ CREATE TABLE `harbormaster_buildplan` ( `dateCreated` int(10) unsigned NOT NULL, `dateModified` int(10) unsigned NOT NULL, `planAutoKey` varchar(32) COLLATE {$COLLATE_TEXT} DEFAULT NULL, + `viewPolicy` varbinary(64) NOT NULL, + `editPolicy` varbinary(64) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `key_phid` (`phid`), UNIQUE KEY `key_planautokey` (`planAutoKey`), @@ -1331,6 +1383,24 @@ CREATE DATABASE /*!32312 IF NOT EXISTS*/ `{$NAMESPACE}_herald` /*!40100 DEFAULT USE `{$NAMESPACE}_herald`; +CREATE TABLE `edge` ( + `src` varbinary(64) NOT NULL, + `type` int(10) unsigned NOT NULL, + `dst` varbinary(64) NOT NULL, + `dateCreated` int(10) unsigned NOT NULL, + `seq` int(10) unsigned NOT NULL, + `dataID` int(10) unsigned DEFAULT NULL, + PRIMARY KEY (`src`,`type`,`dst`), + UNIQUE KEY `key_dst` (`dst`,`type`,`src`), + KEY `src` (`src`,`type`,`dateCreated`,`seq`) +) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE={$COLLATE_TEXT}; + +CREATE TABLE `edgedata` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `data` longtext COLLATE {$COLLATE_TEXT} NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE={$COLLATE_TEXT}; + CREATE TABLE `herald_action` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `ruleID` int(10) unsigned NOT NULL, @@ -1583,10 +1653,11 @@ USE `{$NAMESPACE}_meta_data`; CREATE TABLE `patch_status` ( `patch` varchar(128) COLLATE {$COLLATE_TEXT} NOT NULL, `applied` int(10) unsigned NOT NULL, + `duration` bigint(20) unsigned DEFAULT NULL, PRIMARY KEY (`patch`) ) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE={$COLLATE_TEXT}; -INSERT INTO `patch_status` VALUES ('phabricator:000.project.sql',1443545049),('phabricator:0000.legacy.sql',1443545049),('phabricator:001.maniphest_projects.sql',1443545049),('phabricator:002.oauth.sql',1443545049),('phabricator:003.more_oauth.sql',1443545049),('phabricator:004.daemonrepos.sql',1443545049),('phabricator:005.workers.sql',1443545049),('phabricator:006.repository.sql',1443545049),('phabricator:007.daemonlog.sql',1443545049),('phabricator:008.repoopt.sql',1443545049),('phabricator:009.repo_summary.sql',1443545049),('phabricator:010.herald.sql',1443545049),('phabricator:011.badcommit.sql',1443545049),('phabricator:012.dropphidtype.sql',1443545049),('phabricator:013.commitdetail.sql',1443545049),('phabricator:014.shortcuts.sql',1443545049),('phabricator:015.preferences.sql',1443545049),('phabricator:016.userrealnameindex.sql',1443545049),('phabricator:017.sessionkeys.sql',1443545049),('phabricator:018.owners.sql',1443545049),('phabricator:019.arcprojects.sql',1443545049),('phabricator:020.pathcapital.sql',1443545049),('phabricator:021.xhpastview.sql',1443545049),('phabricator:022.differentialcommit.sql',1443545049),('phabricator:023.dxkeys.sql',1443545049),('phabricator:024.mlistkeys.sql',1443545049),('phabricator:025.commentopt.sql',1443545049),('phabricator:026.diffpropkey.sql',1443545049),('phabricator:027.metamtakeys.sql',1443545049),('phabricator:028.systemagent.sql',1443545049),('phabricator:029.cursors.sql',1443545049),('phabricator:030.imagemacro.sql',1443545049),('phabricator:031.workerrace.sql',1443545049),('phabricator:032.viewtime.sql',1443545049),('phabricator:033.privtest.sql',1443545049),('phabricator:034.savedheader.sql',1443545049),('phabricator:035.proxyimage.sql',1443545049),('phabricator:036.mailkey.sql',1443545049),('phabricator:037.setuptest.sql',1443545049),('phabricator:038.admin.sql',1443545049),('phabricator:039.userlog.sql',1443545050),('phabricator:040.transform.sql',1443545050),('phabricator:041.heraldrepetition.sql',1443545050),('phabricator:042.commentmetadata.sql',1443545050),('phabricator:043.pastebin.sql',1443545050),('phabricator:044.countdown.sql',1443545050),('phabricator:045.timezone.sql',1443545050),('phabricator:046.conduittoken.sql',1443545050),('phabricator:047.projectstatus.sql',1443545050),('phabricator:048.relationshipkeys.sql',1443545050),('phabricator:049.projectowner.sql',1443545050),('phabricator:050.taskdenormal.sql',1443545050),('phabricator:051.projectfilter.sql',1443545050),('phabricator:052.pastelanguage.sql',1443545050),('phabricator:053.feed.sql',1443545050),('phabricator:054.subscribers.sql',1443545050),('phabricator:055.add_author_to_files.sql',1443545050),('phabricator:056.slowvote.sql',1443545050),('phabricator:057.parsecache.sql',1443545050),('phabricator:058.missingkeys.sql',1443545050),('phabricator:059.engines.php',1443545050),('phabricator:060.phriction.sql',1443545050),('phabricator:061.phrictioncontent.sql',1443545050),('phabricator:062.phrictionmenu.sql',1443545050),('phabricator:063.pasteforks.sql',1443545050),('phabricator:064.subprojects.sql',1443545050),('phabricator:065.sshkeys.sql',1443545050),('phabricator:066.phrictioncontent.sql',1443545050),('phabricator:067.preferences.sql',1443545050),('phabricator:068.maniphestauxiliarystorage.sql',1443545050),('phabricator:069.heraldxscript.sql',1443545050),('phabricator:070.differentialaux.sql',1443545050),('phabricator:071.contentsource.sql',1443545050),('phabricator:072.blamerevert.sql',1443545050),('phabricator:073.reposymbols.sql',1443545050),('phabricator:074.affectedpath.sql',1443545050),('phabricator:075.revisionhash.sql',1443545050),('phabricator:076.indexedlanguages.sql',1443545050),('phabricator:077.originalemail.sql',1443545050),('phabricator:078.nametoken.sql',1443545050),('phabricator:079.nametokenindex.php',1443545050),('phabricator:080.filekeys.sql',1443545050),('phabricator:081.filekeys.php',1443545050),('phabricator:082.xactionkey.sql',1443545050),('phabricator:083.dxviewtime.sql',1443545051),('phabricator:084.pasteauthorkey.sql',1443545051),('phabricator:085.packagecommitrelationship.sql',1443545051),('phabricator:086.formeraffil.sql',1443545051),('phabricator:087.phrictiondelete.sql',1443545051),('phabricator:088.audit.sql',1443545051),('phabricator:089.projectwiki.sql',1443545051),('phabricator:090.forceuniqueprojectnames.php',1443545051),('phabricator:091.uniqueslugkey.sql',1443545051),('phabricator:092.dropgithubnotification.sql',1443545051),('phabricator:093.gitremotes.php',1443545051),('phabricator:094.phrictioncolumn.sql',1443545051),('phabricator:095.directory.sql',1443545051),('phabricator:096.filename.sql',1443545051),('phabricator:097.heraldruletypes.sql',1443545051),('phabricator:098.heraldruletypemigration.php',1443545051),('phabricator:099.drydock.sql',1443545051),('phabricator:100.projectxaction.sql',1443545051),('phabricator:101.heraldruleapplied.sql',1443545051),('phabricator:102.heraldcleanup.php',1443545051),('phabricator:103.heraldedithistory.sql',1443545051),('phabricator:104.searchkey.sql',1443545051),('phabricator:105.mimetype.sql',1443545051),('phabricator:106.chatlog.sql',1443545051),('phabricator:107.oauthserver.sql',1443545051),('phabricator:108.oauthscope.sql',1443545051),('phabricator:109.oauthclientphidkey.sql',1443545051),('phabricator:110.commitaudit.sql',1443545051),('phabricator:111.commitauditmigration.php',1443545051),('phabricator:112.oauthaccesscoderedirecturi.sql',1443545051),('phabricator:113.lastreviewer.sql',1443545051),('phabricator:114.auditrequest.sql',1443545051),('phabricator:115.prepareutf8.sql',1443545051),('phabricator:116.utf8-backup-first-expect-wait.sql',1443545053),('phabricator:117.repositorydescription.php',1443545053),('phabricator:118.auditinline.sql',1443545053),('phabricator:119.filehash.sql',1443545053),('phabricator:120.noop.sql',1443545053),('phabricator:121.drydocklog.sql',1443545053),('phabricator:122.flag.sql',1443545053),('phabricator:123.heraldrulelog.sql',1443545053),('phabricator:124.subpriority.sql',1443545053),('phabricator:125.ipv6.sql',1443545053),('phabricator:126.edges.sql',1443545053),('phabricator:127.userkeybody.sql',1443545053),('phabricator:128.phabricatorcom.sql',1443545053),('phabricator:129.savedquery.sql',1443545053),('phabricator:130.denormalrevisionquery.sql',1443545053),('phabricator:131.migraterevisionquery.php',1443545053),('phabricator:132.phame.sql',1443545053),('phabricator:133.imagemacro.sql',1443545053),('phabricator:134.emptysearch.sql',1443545053),('phabricator:135.datecommitted.sql',1443545053),('phabricator:136.sex.sql',1443545053),('phabricator:137.auditmetadata.sql',1443545053),('phabricator:138.notification.sql',1443545053),('phabricator:20121209.pholioxactions.sql',1443545054),('phabricator:20121209.xmacroadd.sql',1443545054),('phabricator:20121209.xmacromigrate.php',1443545054),('phabricator:20121209.xmacromigratekey.sql',1443545054),('phabricator:20121220.generalcache.sql',1443545054),('phabricator:20121226.config.sql',1443545054),('phabricator:20130101.confxaction.sql',1443545054),('phabricator:20130102.metamtareceivedmailmessageidhash.sql',1443545054),('phabricator:20130103.filemetadata.sql',1443545054),('phabricator:20130111.conpherence.sql',1443545054),('phabricator:20130127.altheraldtranscript.sql',1443545054),('phabricator:20130131.conpherencepics.sql',1443545054),('phabricator:20130201.revisionunsubscribed.php',1443545054),('phabricator:20130201.revisionunsubscribed.sql',1443545054),('phabricator:20130214.chatlogchannel.sql',1443545054),('phabricator:20130214.chatlogchannelid.sql',1443545054),('phabricator:20130214.token.sql',1443545054),('phabricator:20130215.phabricatorfileaddttl.sql',1443545054),('phabricator:20130217.cachettl.sql',1443545054),('phabricator:20130218.longdaemon.sql',1443545054),('phabricator:20130218.updatechannelid.php',1443545054),('phabricator:20130219.commitsummary.sql',1443545054),('phabricator:20130219.commitsummarymig.php',1443545054),('phabricator:20130222.dropchannel.sql',1443545054),('phabricator:20130226.commitkey.sql',1443545054),('phabricator:20130304.lintauthor.sql',1443545054),('phabricator:20130310.xactionmeta.sql',1443545055),('phabricator:20130317.phrictionedge.sql',1443545055),('phabricator:20130319.conpherence.sql',1443545054),('phabricator:20130319.phabricatorfileexplicitupload.sql',1443545054),('phabricator:20130320.phlux.sql',1443545055),('phabricator:20130321.token.sql',1443545055),('phabricator:20130322.phortune.sql',1443545055),('phabricator:20130323.phortunepayment.sql',1443545055),('phabricator:20130324.phortuneproduct.sql',1443545055),('phabricator:20130330.phrequent.sql',1443545055),('phabricator:20130403.conpherencecache.sql',1443545055),('phabricator:20130403.conpherencecachemig.php',1443545055),('phabricator:20130409.commitdrev.php',1443545055),('phabricator:20130417.externalaccount.sql',1443545055),('phabricator:20130423.conpherenceindices.sql',1443545055),('phabricator:20130423.phortunepaymentrevised.sql',1443545055),('phabricator:20130423.updateexternalaccount.sql',1443545055),('phabricator:20130426.search_savedquery.sql',1443545055),('phabricator:20130502.countdownrevamp1.sql',1443545055),('phabricator:20130502.countdownrevamp2.php',1443545055),('phabricator:20130502.countdownrevamp3.sql',1443545055),('phabricator:20130507.releephrqmailkey.sql',1443545055),('phabricator:20130507.releephrqmailkeypop.php',1443545055),('phabricator:20130507.releephrqsimplifycols.sql',1443545055),('phabricator:20130508.releephtransactions.sql',1443545055),('phabricator:20130508.releephtransactionsmig.php',1443545055),('phabricator:20130508.search_namedquery.sql',1443545055),('phabricator:20130513.receviedmailstatus.sql',1443545055),('phabricator:20130519.diviner.sql',1443545055),('phabricator:20130521.dropconphimages.sql',1443545055),('phabricator:20130523.maniphest_owners.sql',1443545055),('phabricator:20130524.repoxactions.sql',1443545055),('phabricator:20130529.macroauthor.sql',1443545055),('phabricator:20130529.macroauthormig.php',1443545055),('phabricator:20130530.macrodatekey.sql',1443545055),('phabricator:20130530.pastekeys.sql',1443545055),('phabricator:20130530.sessionhash.php',1443545055),('phabricator:20130531.filekeys.sql',1443545055),('phabricator:20130602.morediviner.sql',1443545055),('phabricator:20130602.namedqueries.sql',1443545055),('phabricator:20130606.userxactions.sql',1443545055),('phabricator:20130607.xaccount.sql',1443545055),('phabricator:20130611.migrateoauth.php',1443545055),('phabricator:20130611.nukeldap.php',1443545055),('phabricator:20130613.authdb.sql',1443545055),('phabricator:20130619.authconf.php',1443545055),('phabricator:20130620.diffxactions.sql',1443545055),('phabricator:20130621.diffcommentphid.sql',1443545055),('phabricator:20130621.diffcommentphidmig.php',1443545055),('phabricator:20130621.diffcommentunphid.sql',1443545056),('phabricator:20130622.doorkeeper.sql',1443545056),('phabricator:20130628.legalpadv0.sql',1443545056),('phabricator:20130701.conduitlog.sql',1443545056),('phabricator:20130703.legalpaddocdenorm.php',1443545056),('phabricator:20130703.legalpaddocdenorm.sql',1443545056),('phabricator:20130709.droptimeline.sql',1443545056),('phabricator:20130709.legalpadsignature.sql',1443545056),('phabricator:20130711.pholioimageobsolete.php',1443545056),('phabricator:20130711.pholioimageobsolete.sql',1443545056),('phabricator:20130711.pholioimageobsolete2.sql',1443545056),('phabricator:20130711.trimrealnames.php',1443545056),('phabricator:20130714.votexactions.sql',1443545056),('phabricator:20130715.votecomments.php',1443545056),('phabricator:20130715.voteedges.sql',1443545056),('phabricator:20130716.archivememberlessprojects.php',1443545056),('phabricator:20130722.pholioreplace.sql',1443545056),('phabricator:20130723.taskstarttime.sql',1443545056),('phabricator:20130726.ponderxactions.sql',1443545056),('phabricator:20130727.ponderquestionstatus.sql',1443545056),('phabricator:20130728.ponderunique.php',1443545056),('phabricator:20130728.ponderuniquekey.sql',1443545056),('phabricator:20130728.ponderxcomment.php',1443545056),('phabricator:20130731.releephcutpointidentifier.sql',1443545056),('phabricator:20130731.releephproject.sql',1443545056),('phabricator:20130731.releephrepoid.sql',1443545056),('phabricator:20130801.pastexactions.php',1443545056),('phabricator:20130801.pastexactions.sql',1443545056),('phabricator:20130802.heraldphid.sql',1443545056),('phabricator:20130802.heraldphids.php',1443545056),('phabricator:20130802.heraldphidukey.sql',1443545056),('phabricator:20130802.heraldxactions.sql',1443545056),('phabricator:20130805.pasteedges.sql',1443545056),('phabricator:20130805.pastemailkey.sql',1443545056),('phabricator:20130805.pastemailkeypop.php',1443545056),('phabricator:20130814.usercustom.sql',1443545056),('phabricator:20130820.file-mailkey-populate.php',1443545056),('phabricator:20130820.filemailkey.sql',1443545056),('phabricator:20130820.filexactions.sql',1443545056),('phabricator:20130820.releephxactions.sql',1443545056),('phabricator:20130826.divinernode.sql',1443545056),('phabricator:20130912.maniphest.1.touch.sql',1443545056),('phabricator:20130912.maniphest.2.created.sql',1443545056),('phabricator:20130912.maniphest.3.nameindex.sql',1443545056),('phabricator:20130912.maniphest.4.fillindex.php',1443545056),('phabricator:20130913.maniphest.1.migratesearch.php',1443545056),('phabricator:20130914.usercustom.sql',1443545056),('phabricator:20130915.maniphestcustom.sql',1443545056),('phabricator:20130915.maniphestmigrate.php',1443545056),('phabricator:20130915.maniphestqdrop.sql',1443545057),('phabricator:20130919.mfieldconf.php',1443545056),('phabricator:20130920.repokeyspolicy.sql',1443545056),('phabricator:20130921.mtransactions.sql',1443545056),('phabricator:20130921.xmigratemaniphest.php',1443545056),('phabricator:20130923.mrename.sql',1443545056),('phabricator:20130924.mdraftkey.sql',1443545056),('phabricator:20130925.mpolicy.sql',1443545056),('phabricator:20130925.xpolicy.sql',1443545057),('phabricator:20130926.dcustom.sql',1443545057),('phabricator:20130926.dinkeys.sql',1443545057),('phabricator:20130926.dinline.php',1443545057),('phabricator:20130927.audiomacro.sql',1443545057),('phabricator:20130929.filepolicy.sql',1443545057),('phabricator:20131004.dxedgekey.sql',1443545057),('phabricator:20131004.dxreviewers.php',1443545057),('phabricator:20131006.hdisable.sql',1443545057),('phabricator:20131010.pstorage.sql',1443545057),('phabricator:20131015.cpolicy.sql',1443545057),('phabricator:20131020.col1.sql',1443545057),('phabricator:20131020.harbormaster.sql',1443545057),('phabricator:20131020.pcustom.sql',1443545057),('phabricator:20131020.pxaction.sql',1443545057),('phabricator:20131020.pxactionmig.php',1443545057),('phabricator:20131025.repopush.sql',1443545057),('phabricator:20131026.commitstatus.sql',1443545057),('phabricator:20131030.repostatusmessage.sql',1443545057),('phabricator:20131031.vcspassword.sql',1443545057),('phabricator:20131105.buildstep.sql',1443545057),('phabricator:20131106.diffphid.1.col.sql',1443545057),('phabricator:20131106.diffphid.2.mig.php',1443545057),('phabricator:20131106.diffphid.3.key.sql',1443545057),('phabricator:20131106.nuance-v0.sql',1443545057),('phabricator:20131107.buildlog.sql',1443545057),('phabricator:20131112.userverified.1.col.sql',1443545057),('phabricator:20131112.userverified.2.mig.php',1443545057),('phabricator:20131118.ownerorder.php',1443545057),('phabricator:20131119.passphrase.sql',1443545057),('phabricator:20131120.nuancesourcetype.sql',1443545057),('phabricator:20131121.passphraseedge.sql',1443545057),('phabricator:20131121.repocredentials.1.col.sql',1443545057),('phabricator:20131121.repocredentials.2.mig.php',1443545057),('phabricator:20131122.repomirror.sql',1443545057),('phabricator:20131123.drydockblueprintpolicy.sql',1443545057),('phabricator:20131129.drydockresourceblueprint.sql',1443545057),('phabricator:20131204.pushlog.sql',1443545057),('phabricator:20131205.buildsteporder.sql',1443545058),('phabricator:20131205.buildstepordermig.php',1443545058),('phabricator:20131205.buildtargets.sql',1443545057),('phabricator:20131206.phragment.sql',1443545058),('phabricator:20131206.phragmentnull.sql',1443545058),('phabricator:20131208.phragmentsnapshot.sql',1443545058),('phabricator:20131211.phragmentedges.sql',1443545058),('phabricator:20131217.pushlogphid.1.col.sql',1443545058),('phabricator:20131217.pushlogphid.2.mig.php',1443545058),('phabricator:20131217.pushlogphid.3.key.sql',1443545058),('phabricator:20131219.pxdrop.sql',1443545058),('phabricator:20131224.harbormanual.sql',1443545058),('phabricator:20131227.heraldobject.sql',1443545058),('phabricator:20131231.dropshortcut.sql',1443545058),('phabricator:20131302.maniphestvalue.sql',1443545054),('phabricator:20140104.harbormastercmd.sql',1443545058),('phabricator:20140106.macromailkey.1.sql',1443545058),('phabricator:20140106.macromailkey.2.php',1443545058),('phabricator:20140108.ddbpname.1.sql',1443545058),('phabricator:20140108.ddbpname.2.php',1443545058),('phabricator:20140109.ddxactions.sql',1443545058),('phabricator:20140109.projectcolumnsdates.sql',1443545058),('phabricator:20140113.legalpadsig.1.sql',1443545058),('phabricator:20140113.legalpadsig.2.php',1443545058),('phabricator:20140115.auth.1.id.sql',1443545058),('phabricator:20140115.auth.2.expires.sql',1443545058),('phabricator:20140115.auth.3.unlimit.php',1443545058),('phabricator:20140115.legalpadsigkey.sql',1443545058),('phabricator:20140116.reporefcursor.sql',1443545058),('phabricator:20140126.diff.1.parentrevisionid.sql',1443545058),('phabricator:20140126.diff.2.repositoryphid.sql',1443545058),('phabricator:20140130.dash.1.board.sql',1443545058),('phabricator:20140130.dash.2.panel.sql',1443545058),('phabricator:20140130.dash.3.boardxaction.sql',1443545058),('phabricator:20140130.dash.4.panelxaction.sql',1443545058),('phabricator:20140130.mail.1.retry.sql',1443545058),('phabricator:20140130.mail.2.next.sql',1443545058),('phabricator:20140201.gc.1.mailsent.sql',1443545058),('phabricator:20140201.gc.2.mailreceived.sql',1443545058),('phabricator:20140205.cal.1.rename.sql',1443545058),('phabricator:20140205.cal.2.phid-col.sql',1443545058),('phabricator:20140205.cal.3.phid-mig.php',1443545058),('phabricator:20140205.cal.4.phid-key.sql',1443545058),('phabricator:20140210.herald.rule-condition-mig.php',1443545058),('phabricator:20140210.projcfield.1.blurb.php',1443545058),('phabricator:20140210.projcfield.2.piccol.sql',1443545058),('phabricator:20140210.projcfield.3.picmig.sql',1443545058),('phabricator:20140210.projcfield.4.memmig.sql',1443545058),('phabricator:20140210.projcfield.5.dropprofile.sql',1443545058),('phabricator:20140211.dx.1.nullablechangesetid.sql',1443545058),('phabricator:20140211.dx.2.migcommenttext.php',1443545058),('phabricator:20140211.dx.3.migsubscriptions.sql',1443545058),('phabricator:20140211.dx.999.drop.relationships.sql',1443545058),('phabricator:20140212.dx.1.armageddon.php',1443545058),('phabricator:20140214.clean.1.legacycommentid.sql',1443545058),('phabricator:20140214.clean.2.dropcomment.sql',1443545058),('phabricator:20140214.clean.3.dropinline.sql',1443545058),('phabricator:20140218.differentialdraft.sql',1443545058),('phabricator:20140218.passwords.1.extend.sql',1443545058),('phabricator:20140218.passwords.2.prefix.sql',1443545058),('phabricator:20140218.passwords.3.vcsextend.sql',1443545058),('phabricator:20140218.passwords.4.vcs.php',1443545058),('phabricator:20140223.bigutf8scratch.sql',1443545058),('phabricator:20140224.dxclean.1.datecommitted.sql',1443545058),('phabricator:20140226.dxcustom.1.fielddata.php',1443545058),('phabricator:20140226.dxcustom.99.drop.sql',1443545058),('phabricator:20140228.dxcomment.1.sql',1443545058),('phabricator:20140305.diviner.1.slugcol.sql',1443545058),('phabricator:20140305.diviner.2.slugkey.sql',1443545058),('phabricator:20140311.mdroplegacy.sql',1443545058),('phabricator:20140314.projectcolumn.1.statuscol.sql',1443545058),('phabricator:20140314.projectcolumn.2.statuskey.sql',1443545058),('phabricator:20140317.mupdatedkey.sql',1443545058),('phabricator:20140321.harbor.1.bxaction.sql',1443545058),('phabricator:20140321.mstatus.1.col.sql',1443545058),('phabricator:20140321.mstatus.2.mig.php',1443545058),('phabricator:20140323.harbor.1.renames.php',1443545058),('phabricator:20140323.harbor.2.message.sql',1443545058),('phabricator:20140325.push.1.event.sql',1443545058),('phabricator:20140325.push.2.eventphid.sql',1443545059),('phabricator:20140325.push.3.groups.php',1443545059),('phabricator:20140325.push.4.prune.sql',1443545059),('phabricator:20140326.project.1.colxaction.sql',1443545059),('phabricator:20140328.releeph.1.productxaction.sql',1443545059),('phabricator:20140330.flagtext.sql',1443545059),('phabricator:20140402.actionlog.sql',1443545059),('phabricator:20140410.accountsecret.1.sql',1443545059),('phabricator:20140410.accountsecret.2.php',1443545059),('phabricator:20140416.harbor.1.sql',1443545059),('phabricator:20140420.rel.1.objectphid.sql',1443545059),('phabricator:20140420.rel.2.objectmig.php',1443545059),('phabricator:20140421.slowvotecolumnsisclosed.sql',1443545059),('phabricator:20140423.session.1.hisec.sql',1443545059),('phabricator:20140427.mfactor.1.sql',1443545059),('phabricator:20140430.auth.1.partial.sql',1443545059),('phabricator:20140430.dash.1.paneltype.sql',1443545059),('phabricator:20140430.dash.2.edge.sql',1443545059),('phabricator:20140501.passphraselockcredential.sql',1443545059),('phabricator:20140501.remove.1.dlog.sql',1443545059),('phabricator:20140507.smstable.sql',1443545059),('phabricator:20140509.coverage.1.sql',1443545059),('phabricator:20140509.dashboardlayoutconfig.sql',1443545059),('phabricator:20140512.dparents.1.sql',1443545059),('phabricator:20140514.harbormasterbuildabletransaction.sql',1443545059),('phabricator:20140514.pholiomockclose.sql',1443545059),('phabricator:20140515.trust-emails.sql',1443545059),('phabricator:20140517.dxbinarycache.sql',1443545059),('phabricator:20140518.dxmorebinarycache.sql',1443545059),('phabricator:20140519.dashboardinstall.sql',1443545059),('phabricator:20140520.authtemptoken.sql',1443545059),('phabricator:20140521.projectslug.1.create.sql',1443545059),('phabricator:20140521.projectslug.2.mig.php',1443545059),('phabricator:20140522.projecticon.sql',1443545059),('phabricator:20140524.auth.mfa.cache.sql',1443545059),('phabricator:20140525.hunkmodern.sql',1443545059),('phabricator:20140615.pholioedit.1.sql',1443545059),('phabricator:20140615.pholioedit.2.sql',1443545059),('phabricator:20140617.daemon.explicit-argv.sql',1443545059),('phabricator:20140617.daemonlog.sql',1443545059),('phabricator:20140624.projcolor.1.sql',1443545059),('phabricator:20140624.projcolor.2.sql',1443545059),('phabricator:20140629.dasharchive.1.sql',1443545059),('phabricator:20140629.legalsig.1.sql',1443545059),('phabricator:20140629.legalsig.2.php',1443545059),('phabricator:20140701.legalexemption.1.sql',1443545059),('phabricator:20140701.legalexemption.2.sql',1443545059),('phabricator:20140703.legalcorp.1.sql',1443545059),('phabricator:20140703.legalcorp.2.sql',1443545059),('phabricator:20140703.legalcorp.3.sql',1443545059),('phabricator:20140703.legalcorp.4.sql',1443545059),('phabricator:20140703.legalcorp.5.sql',1443545059),('phabricator:20140704.harbormasterstep.1.sql',1443545059),('phabricator:20140704.harbormasterstep.2.sql',1443545059),('phabricator:20140704.legalpreamble.1.sql',1443545059),('phabricator:20140706.harbormasterdepend.1.php',1443545059),('phabricator:20140706.pedge.1.sql',1443545059),('phabricator:20140711.pnames.1.sql',1443545059),('phabricator:20140711.pnames.2.php',1443545059),('phabricator:20140711.workerpriority.sql',1443545059),('phabricator:20140712.projcoluniq.sql',1443545059),('phabricator:20140721.phortune.1.cart.sql',1443545059),('phabricator:20140721.phortune.2.purchase.sql',1443545059),('phabricator:20140721.phortune.3.charge.sql',1443545059),('phabricator:20140721.phortune.4.cartstatus.sql',1443545059),('phabricator:20140721.phortune.5.cstatusdefault.sql',1443545059),('phabricator:20140721.phortune.6.onetimecharge.sql',1443545060),('phabricator:20140721.phortune.7.nullmethod.sql',1443545060),('phabricator:20140722.appname.php',1443545060),('phabricator:20140722.audit.1.xactions.sql',1443545060),('phabricator:20140722.audit.2.comments.sql',1443545060),('phabricator:20140722.audit.3.miginlines.php',1443545060),('phabricator:20140722.audit.4.migtext.php',1443545060),('phabricator:20140722.renameauth.php',1443545060),('phabricator:20140723.apprenamexaction.sql',1443545060),('phabricator:20140725.audit.1.migxactions.php',1443545060),('phabricator:20140731.audit.1.subscribers.php',1443545060),('phabricator:20140731.cancdn.php',1443545060),('phabricator:20140731.harbormasterstepdesc.sql',1443545060),('phabricator:20140805.boardcol.1.sql',1443545060),('phabricator:20140805.boardcol.2.php',1443545060),('phabricator:20140807.harbormastertargettime.sql',1443545060),('phabricator:20140808.boardprop.1.sql',1443545060),('phabricator:20140808.boardprop.2.sql',1443545060),('phabricator:20140808.boardprop.3.php',1443545060),('phabricator:20140811.blob.1.sql',1443545060),('phabricator:20140811.blob.2.sql',1443545060),('phabricator:20140812.projkey.1.sql',1443545060),('phabricator:20140812.projkey.2.sql',1443545060),('phabricator:20140814.passphrasecredentialconduit.sql',1443545060),('phabricator:20140815.cancdncase.php',1443545060),('phabricator:20140818.harbormasterindex.1.sql',1443545060),('phabricator:20140821.harbormasterbuildgen.1.sql',1443545060),('phabricator:20140822.daemonenvhash.sql',1443545060),('phabricator:20140902.almanacdevice.1.sql',1443545060),('phabricator:20140904.macroattach.php',1443545060),('phabricator:20140911.fund.1.initiative.sql',1443545060),('phabricator:20140911.fund.2.xaction.sql',1443545060),('phabricator:20140911.fund.3.edge.sql',1443545060),('phabricator:20140911.fund.4.backer.sql',1443545060),('phabricator:20140911.fund.5.backxaction.sql',1443545060),('phabricator:20140914.betaproto.php',1443545060),('phabricator:20140917.project.canlock.sql',1443545060),('phabricator:20140918.schema.1.dropaudit.sql',1443545060),('phabricator:20140918.schema.2.dropauditinline.sql',1443545060),('phabricator:20140918.schema.3.wipecache.sql',1443545060),('phabricator:20140918.schema.4.cachetype.sql',1443545060),('phabricator:20140918.schema.5.slowvote.sql',1443545060),('phabricator:20140919.schema.01.calstatus.sql',1443545060),('phabricator:20140919.schema.02.calname.sql',1443545060),('phabricator:20140919.schema.03.dropaux.sql',1443545060),('phabricator:20140919.schema.04.droptaskproj.sql',1443545060),('phabricator:20140926.schema.01.droprelev.sql',1443545060),('phabricator:20140926.schema.02.droprelreqev.sql',1443545060),('phabricator:20140926.schema.03.dropldapinfo.sql',1443545060),('phabricator:20140926.schema.04.dropoauthinfo.sql',1443545060),('phabricator:20140926.schema.05.dropprojaffil.sql',1443545060),('phabricator:20140926.schema.06.dropsubproject.sql',1443545060),('phabricator:20140926.schema.07.droppondcom.sql',1443545060),('phabricator:20140927.schema.01.dropsearchq.sql',1443545060),('phabricator:20140927.schema.02.pholio1.sql',1443545060),('phabricator:20140927.schema.03.pholio2.sql',1443545060),('phabricator:20140927.schema.04.pholio3.sql',1443545060),('phabricator:20140927.schema.05.phragment1.sql',1443545060),('phabricator:20140927.schema.06.releeph1.sql',1443545060),('phabricator:20141001.schema.01.version.sql',1443545060),('phabricator:20141001.schema.02.taskmail.sql',1443545060),('phabricator:20141002.schema.01.liskcounter.sql',1443545060),('phabricator:20141002.schema.02.draftnull.sql',1443545060),('phabricator:20141004.currency.01.sql',1443545060),('phabricator:20141004.currency.02.sql',1443545060),('phabricator:20141004.currency.03.sql',1443545060),('phabricator:20141004.currency.04.sql',1443545060),('phabricator:20141004.currency.05.sql',1443545060),('phabricator:20141004.currency.06.sql',1443545060),('phabricator:20141004.harborliskcounter.sql',1443545060),('phabricator:20141005.phortuneproduct.sql',1443545060),('phabricator:20141006.phortunecart.sql',1443545060),('phabricator:20141006.phortunemerchant.sql',1443545060),('phabricator:20141006.phortunemerchantx.sql',1443545060),('phabricator:20141007.fundmerchant.sql',1443545060),('phabricator:20141007.fundrisks.sql',1443545060),('phabricator:20141007.fundtotal.sql',1443545060),('phabricator:20141007.phortunecartmerchant.sql',1443545060),('phabricator:20141007.phortunecharge.sql',1443545061),('phabricator:20141007.phortunepayment.sql',1443545061),('phabricator:20141007.phortuneprovider.sql',1443545061),('phabricator:20141007.phortuneproviderx.sql',1443545061),('phabricator:20141008.phortunemerchdesc.sql',1443545061),('phabricator:20141008.phortuneprovdis.sql',1443545061),('phabricator:20141008.phortunerefund.sql',1443545061),('phabricator:20141010.fundmailkey.sql',1443545061),('phabricator:20141011.phortunemerchedit.sql',1443545061),('phabricator:20141012.phortunecartxaction.sql',1443545061),('phabricator:20141013.phortunecartkey.sql',1443545061),('phabricator:20141016.almanac.device.sql',1443545061),('phabricator:20141016.almanac.dxaction.sql',1443545061),('phabricator:20141016.almanac.interface.sql',1443545061),('phabricator:20141016.almanac.network.sql',1443545061),('phabricator:20141016.almanac.nxaction.sql',1443545061),('phabricator:20141016.almanac.service.sql',1443545061),('phabricator:20141016.almanac.sxaction.sql',1443545061),('phabricator:20141017.almanac.binding.sql',1443545061),('phabricator:20141017.almanac.bxaction.sql',1443545061),('phabricator:20141025.phriction.1.xaction.sql',1443545061),('phabricator:20141025.phriction.2.xaction.sql',1443545061),('phabricator:20141025.phriction.mailkey.sql',1443545061),('phabricator:20141103.almanac.1.delprop.sql',1443545061),('phabricator:20141103.almanac.2.addprop.sql',1443545061),('phabricator:20141104.almanac.3.edge.sql',1443545061),('phabricator:20141105.ssh.1.rename.sql',1443545061),('phabricator:20141106.dropold.sql',1443545061),('phabricator:20141106.uniqdrafts.php',1443545061),('phabricator:20141107.phriction.policy.1.sql',1443545061),('phabricator:20141107.phriction.policy.2.php',1443545061),('phabricator:20141107.phriction.popkeys.php',1443545061),('phabricator:20141107.ssh.1.colname.sql',1443545061),('phabricator:20141107.ssh.2.keyhash.sql',1443545061),('phabricator:20141107.ssh.3.keyindex.sql',1443545061),('phabricator:20141107.ssh.4.keymig.php',1443545061),('phabricator:20141107.ssh.5.indexnull.sql',1443545061),('phabricator:20141107.ssh.6.indexkey.sql',1443545061),('phabricator:20141107.ssh.7.colnull.sql',1443545061),('phabricator:20141113.auditdupes.php',1443545061),('phabricator:20141118.diffxaction.sql',1443545061),('phabricator:20141119.commitpedge.sql',1443545061),('phabricator:20141119.differential.diff.policy.sql',1443545061),('phabricator:20141119.sshtrust.sql',1443545061),('phabricator:20141123.taskpriority.1.sql',1443545061),('phabricator:20141123.taskpriority.2.sql',1443545061),('phabricator:20141210.maniphestsubscribersmig.1.sql',1443545061),('phabricator:20141210.maniphestsubscribersmig.2.sql',1443545061),('phabricator:20141210.reposervice.sql',1443545061),('phabricator:20141212.conduittoken.sql',1443545061),('phabricator:20141215.almanacservicetype.sql',1443545061),('phabricator:20141217.almanacdevicelock.sql',1443545061),('phabricator:20141217.almanaclock.sql',1443545061),('phabricator:20141218.maniphestcctxn.php',1443545061),('phabricator:20141222.maniphestprojtxn.php',1443545061),('phabricator:20141223.daemonloguser.sql',1443545061),('phabricator:20141223.daemonobjectphid.sql',1443545061),('phabricator:20141230.pasteeditpolicycolumn.sql',1443545061),('phabricator:20141230.pasteeditpolicyexisting.sql',1443545061),('phabricator:20150102.policyname.php',1443545061),('phabricator:20150102.tasksubscriber.sql',1443545061),('phabricator:20150105.conpsearch.sql',1443545061),('phabricator:20150114.oauthserver.client.policy.sql',1443545062),('phabricator:20150115.applicationemails.sql',1443545062),('phabricator:20150115.trigger.1.sql',1443545062),('phabricator:20150115.trigger.2.sql',1443545062),('phabricator:20150116.maniphestapplicationemails.php',1443545062),('phabricator:20150120.maniphestdefaultauthor.php',1443545062),('phabricator:20150124.subs.1.sql',1443545062),('phabricator:20150129.pastefileapplicationemails.php',1443545062),('phabricator:20150130.phortune.1.subphid.sql',1443545062),('phabricator:20150130.phortune.2.subkey.sql',1443545062),('phabricator:20150131.phortune.1.defaultpayment.sql',1443545062),('phabricator:20150205.authprovider.autologin.sql',1443545062),('phabricator:20150205.daemonenv.sql',1443545062),('phabricator:20150209.invite.sql',1443545062),('phabricator:20150209.oauthclient.trust.sql',1443545062),('phabricator:20150210.invitephid.sql',1443545062),('phabricator:20150212.legalpad.session.1.sql',1443545062),('phabricator:20150212.legalpad.session.2.sql',1443545062),('phabricator:20150219.scratch.nonmutable.sql',1443545062),('phabricator:20150223.daemon.1.id.sql',1443545062),('phabricator:20150223.daemon.2.idlegacy.sql',1443545062),('phabricator:20150223.daemon.3.idkey.sql',1443545062),('phabricator:20150312.filechunk.1.sql',1443545062),('phabricator:20150312.filechunk.2.sql',1443545062),('phabricator:20150312.filechunk.3.sql',1443545062),('phabricator:20150317.conpherence.isroom.1.sql',1443545062),('phabricator:20150317.conpherence.isroom.2.sql',1443545062),('phabricator:20150317.conpherence.policy.sql',1443545062),('phabricator:20150410.nukeruleedit.sql',1443545062),('phabricator:20150420.invoice.1.sql',1443545062),('phabricator:20150420.invoice.2.sql',1443545062),('phabricator:20150425.isclosed.sql',1443545062),('phabricator:20150427.calendar.1.edge.sql',1443545062),('phabricator:20150427.calendar.1.xaction.sql',1443545062),('phabricator:20150427.calendar.2.xaction.sql',1443545062),('phabricator:20150428.calendar.1.iscancelled.sql',1443545062),('phabricator:20150428.calendar.1.name.sql',1443545062),('phabricator:20150429.calendar.1.invitee.sql',1443545062),('phabricator:20150430.calendar.1.policies.sql',1443545062),('phabricator:20150430.multimeter.1.sql',1443545062),('phabricator:20150430.multimeter.2.host.sql',1443545062),('phabricator:20150430.multimeter.3.viewer.sql',1443545062),('phabricator:20150430.multimeter.4.context.sql',1443545062),('phabricator:20150430.multimeter.5.label.sql',1443545062),('phabricator:20150501.calendar.1.reply.sql',1443545062),('phabricator:20150501.calendar.2.reply.php',1443545062),('phabricator:20150501.conpherencepics.sql',1443545062),('phabricator:20150503.repositorysymbols.1.sql',1443545062),('phabricator:20150503.repositorysymbols.2.php',1443545062),('phabricator:20150503.repositorysymbols.3.sql',1443545062),('phabricator:20150504.symbolsproject.1.php',1443545062),('phabricator:20150504.symbolsproject.2.sql',1443545062),('phabricator:20150506.calendarunnamedevents.1.php',1443545062),('phabricator:20150507.calendar.1.isallday.sql',1443545062),('phabricator:20150513.user.cache.1.sql',1443545062),('phabricator:20150514.calendar.status.sql',1443545062),('phabricator:20150514.phame.blog.xaction.sql',1443545062),('phabricator:20150514.user.cache.2.sql',1443545062),('phabricator:20150515.phame.post.xaction.sql',1443545062),('phabricator:20150515.project.mailkey.1.sql',1443545062),('phabricator:20150515.project.mailkey.2.php',1443545062),('phabricator:20150519.calendar.calendaricon.sql',1443545062),('phabricator:20150521.releephrepository.sql',1443545062),('phabricator:20150525.diff.hidden.1.sql',1443545062),('phabricator:20150526.owners.mailkey.1.sql',1443545062),('phabricator:20150526.owners.mailkey.2.php',1443545062),('phabricator:20150526.owners.xaction.sql',1443545062),('phabricator:20150527.calendar.recurringevents.sql',1443545062),('phabricator:20150601.spaces.1.namespace.sql',1443545063),('phabricator:20150601.spaces.2.xaction.sql',1443545063),('phabricator:20150602.mlist.1.sql',1443545063),('phabricator:20150602.mlist.2.php',1443545063),('phabricator:20150604.spaces.1.sql',1443545063),('phabricator:20150605.diviner.edges.sql',1443545063),('phabricator:20150605.diviner.editPolicy.sql',1443545063),('phabricator:20150605.diviner.xaction.sql',1443545063),('phabricator:20150606.mlist.1.php',1443545063),('phabricator:20150609.inline.sql',1443545063),('phabricator:20150609.spaces.1.pholio.sql',1443545063),('phabricator:20150609.spaces.2.maniphest.sql',1443545063),('phabricator:20150610.spaces.1.desc.sql',1443545063),('phabricator:20150610.spaces.2.edge.sql',1443545063),('phabricator:20150610.spaces.3.archive.sql',1443545063),('phabricator:20150611.spaces.1.mailxaction.sql',1443545063),('phabricator:20150611.spaces.2.appmail.sql',1443545063),('phabricator:20150616.divinerrepository.sql',1443545063),('phabricator:20150617.harbor.1.lint.sql',1443545063),('phabricator:20150617.harbor.2.unit.sql',1443545063),('phabricator:20150618.harbor.1.planauto.sql',1443545063),('phabricator:20150618.harbor.2.stepauto.sql',1443545063),('phabricator:20150618.harbor.3.buildauto.sql',1443545063),('phabricator:20150619.conpherencerooms.1.sql',1443545063),('phabricator:20150619.conpherencerooms.2.sql',1443545063),('phabricator:20150619.conpherencerooms.3.sql',1443545063),('phabricator:20150621.phrase.1.sql',1443545063),('phabricator:20150621.phrase.2.sql',1443545063),('phabricator:20150622.bulk.1.job.sql',1443545063),('phabricator:20150622.bulk.2.task.sql',1443545063),('phabricator:20150622.bulk.3.xaction.sql',1443545063),('phabricator:20150622.bulk.4.edge.sql',1443545063),('phabricator:20150622.metamta.1.phid-col.sql',1443545063),('phabricator:20150622.metamta.2.phid-mig.php',1443545063),('phabricator:20150622.metamta.3.phid-key.sql',1443545063),('phabricator:20150622.metamta.4.actor-phid-col.sql',1443545063),('phabricator:20150622.metamta.5.actor-phid-mig.php',1443545063),('phabricator:20150622.metamta.6.actor-phid-key.sql',1443545063),('phabricator:20150624.spaces.1.repo.sql',1443545063),('phabricator:20150626.spaces.1.calendar.sql',1443545063),('phabricator:20150630.herald.1.sql',1443545063),('phabricator:20150630.herald.2.sql',1443545063),('phabricator:20150701.herald.1.sql',1443545063),('phabricator:20150701.herald.2.sql',1443545063),('phabricator:20150702.spaces.1.slowvote.sql',1443545063),('phabricator:20150706.herald.1.sql',1443545063),('phabricator:20150707.herald.1.sql',1443545063),('phabricator:20150708.arcanistproject.sql',1443545063),('phabricator:20150708.herald.1.sql',1443545063),('phabricator:20150708.herald.2.sql',1443545063),('phabricator:20150708.herald.3.sql',1443545063),('phabricator:20150712.badges.1.sql',1443545063),('phabricator:20150714.spaces.countdown.1.sql',1443545063),('phabricator:20150717.herald.1.sql',1443545063),('phabricator:20150719.countdown.1.sql',1443545063),('phabricator:20150719.countdown.2.sql',1443545063),('phabricator:20150719.countdown.3.sql',1443545063),('phabricator:20150721.phurl.1.url.sql',1443545063),('phabricator:20150721.phurl.2.xaction.sql',1443545063),('phabricator:20150721.phurl.3.xactioncomment.sql',1443545063),('phabricator:20150721.phurl.4.url.sql',1443545063),('phabricator:20150721.phurl.5.edge.sql',1443545063),('phabricator:20150721.phurl.6.alias.sql',1443545063),('phabricator:20150721.phurl.7.authorphid.sql',1443545063),('phabricator:20150722.dashboard.1.sql',1443545063),('phabricator:20150722.dashboard.2.sql',1443545063),('phabricator:20150723.countdown.1.sql',1443545063),('phabricator:20150724.badges.comments.1.sql',1443545063),('phabricator:20150724.countdown.comments.1.sql',1443545063),('phabricator:20150725.badges.mailkey.1.sql',1443545063),('phabricator:20150725.badges.mailkey.2.php',1443545063),('phabricator:20150725.badges.viewpolicy.3.sql',1443545063),('phabricator:20150725.countdown.mailkey.1.sql',1443545063),('phabricator:20150725.countdown.mailkey.2.php',1443545063),('phabricator:20150725.slowvote.mailkey.1.sql',1443545063),('phabricator:20150725.slowvote.mailkey.2.php',1443545063),('phabricator:20150727.heraldaction.1.sql',1443545063),('phabricator:20150730.herald.1.sql',1443545063),('phabricator:20150730.herald.2.sql',1443545063),('phabricator:20150730.herald.3.sql',1443545063),('phabricator:20150730.herald.4.sql',1443545063),('phabricator:20150730.herald.5.sql',1443545063),('phabricator:20150730.herald.6.sql',1443545063),('phabricator:20150730.herald.7.sql',1443545063),('phabricator:20150803.herald.1.sql',1443545063),('phabricator:20150803.herald.2.sql',1443545063),('phabricator:20150804.ponder.answer.mailkey.1.sql',1443545063),('phabricator:20150804.ponder.answer.mailkey.2.php',1443545063),('phabricator:20150804.ponder.question.1.sql',1443545064),('phabricator:20150804.ponder.question.2.sql',1443545064),('phabricator:20150804.ponder.question.3.sql',1443545064),('phabricator:20150804.ponder.spaces.4.sql',1443545064),('phabricator:20150805.paste.status.1.sql',1443545064),('phabricator:20150805.paste.status.2.sql',1443545064),('phabricator:20150806.ponder.answer.1.sql',1443545064),('phabricator:20150806.ponder.editpolicy.2.sql',1443545064),('phabricator:20150806.ponder.status.1.sql',1443545064),('phabricator:20150806.ponder.status.2.sql',1443545064),('phabricator:20150806.ponder.status.3.sql',1443545064),('phabricator:20150808.ponder.vote.1.sql',1443545064),('phabricator:20150808.ponder.vote.2.sql',1443545064),('phabricator:20150812.ponder.answer.1.sql',1443545064),('phabricator:20150812.ponder.answer.2.sql',1443545064),('phabricator:20150814.harbormater.artifact.phid.sql',1443545064),('phabricator:20150815.owners.status.1.sql',1443545064),('phabricator:20150815.owners.status.2.sql',1443545064),('phabricator:20150823.nuance.queue.1.sql',1443545064),('phabricator:20150823.nuance.queue.2.sql',1443545064),('phabricator:20150823.nuance.queue.3.sql',1443545064),('phabricator:20150823.nuance.queue.4.sql',1443545064),('phabricator:20150828.ponder.wiki.1.sql',1443545064),('phabricator:20150829.ponder.dupe.1.sql',1443545064),('phabricator:20150904.herald.1.sql',1443545064),('phabricator:20150910.owners.custom.1.sql',1443545064),('phabricator:20150916.drydock.slotlocks.1.sql',1443545064),('phabricator:20150922.drydock.commands.1.sql',1443545064),('phabricator:20150923.drydock.resourceid.1.sql',1443545064),('phabricator:20150923.drydock.resourceid.2.sql',1443545064),('phabricator:20150923.drydock.resourceid.3.sql',1443545064),('phabricator:20150923.drydock.taskid.1.sql',1443545064),('phabricator:20150924.drydock.disable.1.sql',1443545064),('phabricator:20150924.drydock.status.1.sql',1443545064),('phabricator:20150928.drydock.rexpire.1.sql',1443545064),('phabricator:daemonstatus.sql',1443545053),('phabricator:daemonstatuskey.sql',1443545054),('phabricator:daemontaskarchive.sql',1443545054),('phabricator:db.almanac',1443545048),('phabricator:db.audit',1443545048),('phabricator:db.auth',1443545048),('phabricator:db.badges',1443545048),('phabricator:db.cache',1443545048),('phabricator:db.calendar',1443545048),('phabricator:db.chatlog',1443545048),('phabricator:db.conduit',1443545048),('phabricator:db.config',1443545048),('phabricator:db.conpherence',1443545048),('phabricator:db.countdown',1443545048),('phabricator:db.daemon',1443545048),('phabricator:db.dashboard',1443545048),('phabricator:db.differential',1443545048),('phabricator:db.diviner',1443545048),('phabricator:db.doorkeeper',1443545048),('phabricator:db.draft',1443545048),('phabricator:db.drydock',1443545048),('phabricator:db.fact',1443545048),('phabricator:db.feed',1443545048),('phabricator:db.file',1443545048),('phabricator:db.flag',1443545048),('phabricator:db.fund',1443545048),('phabricator:db.harbormaster',1443545048),('phabricator:db.herald',1443545048),('phabricator:db.legalpad',1443545048),('phabricator:db.maniphest',1443545048),('phabricator:db.meta_data',1443545048),('phabricator:db.metamta',1443545048),('phabricator:db.multimeter',1443545048),('phabricator:db.nuance',1443545048),('phabricator:db.oauth_server',1443545048),('phabricator:db.owners',1443545048),('phabricator:db.passphrase',1443545048),('phabricator:db.pastebin',1443545048),('phabricator:db.phame',1443545048),('phabricator:db.phlux',1443545048),('phabricator:db.pholio',1443545048),('phabricator:db.phortune',1443545048),('phabricator:db.phragment',1443545048),('phabricator:db.phrequent',1443545048),('phabricator:db.phriction',1443545048),('phabricator:db.phurl',1443545048),('phabricator:db.policy',1443545048),('phabricator:db.ponder',1443545048),('phabricator:db.project',1443545048),('phabricator:db.releeph',1443545048),('phabricator:db.repository',1443545048),('phabricator:db.search',1443545048),('phabricator:db.slowvote',1443545048),('phabricator:db.spaces',1443545048),('phabricator:db.system',1443545048),('phabricator:db.timeline',1443545048),('phabricator:db.token',1443545048),('phabricator:db.user',1443545048),('phabricator:db.worker',1443545048),('phabricator:db.xhpastview',1443545048),('phabricator:db.xhprof',1443545048),('phabricator:differentialbookmarks.sql',1443545053),('phabricator:draft-metadata.sql',1443545054),('phabricator:dropfileproxyimage.sql',1443545054),('phabricator:drydockresoucetype.sql',1443545054),('phabricator:drydocktaskid.sql',1443545054),('phabricator:edgetype.sql',1443545054),('phabricator:emailtable.sql',1443545053),('phabricator:emailtableport.sql',1443545053),('phabricator:emailtableremove.sql',1443545053),('phabricator:fact-raw.sql',1443545053),('phabricator:harbormasterobject.sql',1443545053),('phabricator:holidays.sql',1443545053),('phabricator:ldapinfo.sql',1443545053),('phabricator:legalpad-mailkey-populate.php',1443545056),('phabricator:legalpad-mailkey.sql',1443545056),('phabricator:liskcounters-task.sql',1443545054),('phabricator:liskcounters.php',1443545054),('phabricator:liskcounters.sql',1443545054),('phabricator:maniphestxcache.sql',1443545053),('phabricator:markupcache.sql',1443545053),('phabricator:migrate-differential-dependencies.php',1443545053),('phabricator:migrate-maniphest-dependencies.php',1443545053),('phabricator:migrate-maniphest-revisions.php',1443545053),('phabricator:migrate-project-edges.php',1443545053),('phabricator:owners-exclude.sql',1443545054),('phabricator:pastepolicy.sql',1443545054),('phabricator:phameblog.sql',1443545053),('phabricator:phamedomain.sql',1443545054),('phabricator:phameoneblog.sql',1443545054),('phabricator:phamepolicy.sql',1443545054),('phabricator:phiddrop.sql',1443545053),('phabricator:pholio.sql',1443545054),('phabricator:policy-project.sql',1443545054),('phabricator:ponder-comments.sql',1443545054),('phabricator:ponder-mailkey-populate.php',1443545054),('phabricator:ponder-mailkey.sql',1443545054),('phabricator:ponder.sql',1443545054),('phabricator:releeph.sql',1443545054),('phabricator:repository-lint.sql',1443545054),('phabricator:statustxt.sql',1443545054),('phabricator:symbolcontexts.sql',1443545053),('phabricator:testdatabase.sql',1443545053),('phabricator:threadtopic.sql',1443545053),('phabricator:userstatus.sql',1443545053),('phabricator:usertranslation.sql',1443545053),('phabricator:xhprof.sql',1443545054); +INSERT INTO `patch_status` VALUES ('phabricator:000.project.sql',1453226118,NULL),('phabricator:0000.legacy.sql',1453226118,NULL),('phabricator:001.maniphest_projects.sql',1453226118,NULL),('phabricator:002.oauth.sql',1453226118,NULL),('phabricator:003.more_oauth.sql',1453226118,NULL),('phabricator:004.daemonrepos.sql',1453226118,NULL),('phabricator:005.workers.sql',1453226118,NULL),('phabricator:006.repository.sql',1453226118,NULL),('phabricator:007.daemonlog.sql',1453226118,NULL),('phabricator:008.repoopt.sql',1453226118,NULL),('phabricator:009.repo_summary.sql',1453226118,NULL),('phabricator:010.herald.sql',1453226118,NULL),('phabricator:011.badcommit.sql',1453226118,NULL),('phabricator:012.dropphidtype.sql',1453226118,NULL),('phabricator:013.commitdetail.sql',1453226118,NULL),('phabricator:014.shortcuts.sql',1453226118,NULL),('phabricator:015.preferences.sql',1453226118,NULL),('phabricator:016.userrealnameindex.sql',1453226118,NULL),('phabricator:017.sessionkeys.sql',1453226118,NULL),('phabricator:018.owners.sql',1453226118,NULL),('phabricator:019.arcprojects.sql',1453226118,NULL),('phabricator:020.pathcapital.sql',1453226118,NULL),('phabricator:021.xhpastview.sql',1453226118,NULL),('phabricator:022.differentialcommit.sql',1453226118,NULL),('phabricator:023.dxkeys.sql',1453226118,NULL),('phabricator:024.mlistkeys.sql',1453226118,NULL),('phabricator:025.commentopt.sql',1453226118,NULL),('phabricator:026.diffpropkey.sql',1453226118,NULL),('phabricator:027.metamtakeys.sql',1453226118,NULL),('phabricator:028.systemagent.sql',1453226118,NULL),('phabricator:029.cursors.sql',1453226118,NULL),('phabricator:030.imagemacro.sql',1453226118,NULL),('phabricator:031.workerrace.sql',1453226118,NULL),('phabricator:032.viewtime.sql',1453226118,NULL),('phabricator:033.privtest.sql',1453226118,NULL),('phabricator:034.savedheader.sql',1453226118,NULL),('phabricator:035.proxyimage.sql',1453226118,NULL),('phabricator:036.mailkey.sql',1453226119,NULL),('phabricator:037.setuptest.sql',1453226119,NULL),('phabricator:038.admin.sql',1453226119,NULL),('phabricator:039.userlog.sql',1453226119,NULL),('phabricator:040.transform.sql',1453226119,NULL),('phabricator:041.heraldrepetition.sql',1453226119,NULL),('phabricator:042.commentmetadata.sql',1453226119,NULL),('phabricator:043.pastebin.sql',1453226119,NULL),('phabricator:044.countdown.sql',1453226119,NULL),('phabricator:045.timezone.sql',1453226119,NULL),('phabricator:046.conduittoken.sql',1453226119,NULL),('phabricator:047.projectstatus.sql',1453226119,NULL),('phabricator:048.relationshipkeys.sql',1453226119,NULL),('phabricator:049.projectowner.sql',1453226119,NULL),('phabricator:050.taskdenormal.sql',1453226119,NULL),('phabricator:051.projectfilter.sql',1453226119,NULL),('phabricator:052.pastelanguage.sql',1453226119,NULL),('phabricator:053.feed.sql',1453226119,NULL),('phabricator:054.subscribers.sql',1453226119,NULL),('phabricator:055.add_author_to_files.sql',1453226119,NULL),('phabricator:056.slowvote.sql',1453226119,NULL),('phabricator:057.parsecache.sql',1453226119,NULL),('phabricator:058.missingkeys.sql',1453226119,NULL),('phabricator:059.engines.php',1453226120,NULL),('phabricator:060.phriction.sql',1453226120,NULL),('phabricator:061.phrictioncontent.sql',1453226120,NULL),('phabricator:062.phrictionmenu.sql',1453226120,NULL),('phabricator:063.pasteforks.sql',1453226120,NULL),('phabricator:064.subprojects.sql',1453226120,NULL),('phabricator:065.sshkeys.sql',1453226120,NULL),('phabricator:066.phrictioncontent.sql',1453226120,NULL),('phabricator:067.preferences.sql',1453226120,NULL),('phabricator:068.maniphestauxiliarystorage.sql',1453226120,NULL),('phabricator:069.heraldxscript.sql',1453226120,NULL),('phabricator:070.differentialaux.sql',1453226120,NULL),('phabricator:071.contentsource.sql',1453226120,NULL),('phabricator:072.blamerevert.sql',1453226120,NULL),('phabricator:073.reposymbols.sql',1453226120,NULL),('phabricator:074.affectedpath.sql',1453226120,NULL),('phabricator:075.revisionhash.sql',1453226120,NULL),('phabricator:076.indexedlanguages.sql',1453226120,NULL),('phabricator:077.originalemail.sql',1453226120,NULL),('phabricator:078.nametoken.sql',1453226120,NULL),('phabricator:079.nametokenindex.php',1453226120,NULL),('phabricator:080.filekeys.sql',1453226120,NULL),('phabricator:081.filekeys.php',1453226120,NULL),('phabricator:082.xactionkey.sql',1453226120,NULL),('phabricator:083.dxviewtime.sql',1453226120,NULL),('phabricator:084.pasteauthorkey.sql',1453226120,NULL),('phabricator:085.packagecommitrelationship.sql',1453226120,NULL),('phabricator:086.formeraffil.sql',1453226120,NULL),('phabricator:087.phrictiondelete.sql',1453226120,NULL),('phabricator:088.audit.sql',1453226120,NULL),('phabricator:089.projectwiki.sql',1453226120,NULL),('phabricator:090.forceuniqueprojectnames.php',1453226120,NULL),('phabricator:091.uniqueslugkey.sql',1453226120,NULL),('phabricator:092.dropgithubnotification.sql',1453226120,NULL),('phabricator:093.gitremotes.php',1453226120,NULL),('phabricator:094.phrictioncolumn.sql',1453226120,NULL),('phabricator:095.directory.sql',1453226120,NULL),('phabricator:096.filename.sql',1453226120,NULL),('phabricator:097.heraldruletypes.sql',1453226120,NULL),('phabricator:098.heraldruletypemigration.php',1453226120,NULL),('phabricator:099.drydock.sql',1453226120,NULL),('phabricator:100.projectxaction.sql',1453226120,NULL),('phabricator:101.heraldruleapplied.sql',1453226120,NULL),('phabricator:102.heraldcleanup.php',1453226120,NULL),('phabricator:103.heraldedithistory.sql',1453226120,NULL),('phabricator:104.searchkey.sql',1453226120,NULL),('phabricator:105.mimetype.sql',1453226120,NULL),('phabricator:106.chatlog.sql',1453226120,NULL),('phabricator:107.oauthserver.sql',1453226120,NULL),('phabricator:108.oauthscope.sql',1453226120,NULL),('phabricator:109.oauthclientphidkey.sql',1453226120,NULL),('phabricator:110.commitaudit.sql',1453226121,NULL),('phabricator:111.commitauditmigration.php',1453226121,NULL),('phabricator:112.oauthaccesscoderedirecturi.sql',1453226121,NULL),('phabricator:113.lastreviewer.sql',1453226121,NULL),('phabricator:114.auditrequest.sql',1453226121,NULL),('phabricator:115.prepareutf8.sql',1453226121,NULL),('phabricator:116.utf8-backup-first-expect-wait.sql',1453226122,NULL),('phabricator:117.repositorydescription.php',1453226122,NULL),('phabricator:118.auditinline.sql',1453226122,NULL),('phabricator:119.filehash.sql',1453226123,NULL),('phabricator:120.noop.sql',1453226123,NULL),('phabricator:121.drydocklog.sql',1453226123,NULL),('phabricator:122.flag.sql',1453226123,NULL),('phabricator:123.heraldrulelog.sql',1453226123,NULL),('phabricator:124.subpriority.sql',1453226123,NULL),('phabricator:125.ipv6.sql',1453226123,NULL),('phabricator:126.edges.sql',1453226123,NULL),('phabricator:127.userkeybody.sql',1453226123,NULL),('phabricator:128.phabricatorcom.sql',1453226123,NULL),('phabricator:129.savedquery.sql',1453226123,NULL),('phabricator:130.denormalrevisionquery.sql',1453226123,NULL),('phabricator:131.migraterevisionquery.php',1453226123,NULL),('phabricator:132.phame.sql',1453226123,NULL),('phabricator:133.imagemacro.sql',1453226123,NULL),('phabricator:134.emptysearch.sql',1453226123,NULL),('phabricator:135.datecommitted.sql',1453226123,NULL),('phabricator:136.sex.sql',1453226123,NULL),('phabricator:137.auditmetadata.sql',1453226123,NULL),('phabricator:138.notification.sql',1453226123,NULL),('phabricator:20121209.pholioxactions.sql',1453226124,NULL),('phabricator:20121209.xmacroadd.sql',1453226124,NULL),('phabricator:20121209.xmacromigrate.php',1453226124,NULL),('phabricator:20121209.xmacromigratekey.sql',1453226124,NULL),('phabricator:20121220.generalcache.sql',1453226124,NULL),('phabricator:20121226.config.sql',1453226124,NULL),('phabricator:20130101.confxaction.sql',1453226124,NULL),('phabricator:20130102.metamtareceivedmailmessageidhash.sql',1453226124,NULL),('phabricator:20130103.filemetadata.sql',1453226124,NULL),('phabricator:20130111.conpherence.sql',1453226124,NULL),('phabricator:20130127.altheraldtranscript.sql',1453226124,NULL),('phabricator:20130131.conpherencepics.sql',1453226124,NULL),('phabricator:20130201.revisionunsubscribed.php',1453226124,NULL),('phabricator:20130201.revisionunsubscribed.sql',1453226124,NULL),('phabricator:20130214.chatlogchannel.sql',1453226124,NULL),('phabricator:20130214.chatlogchannelid.sql',1453226124,NULL),('phabricator:20130214.token.sql',1453226124,NULL),('phabricator:20130215.phabricatorfileaddttl.sql',1453226124,NULL),('phabricator:20130217.cachettl.sql',1453226124,NULL),('phabricator:20130218.longdaemon.sql',1453226124,NULL),('phabricator:20130218.updatechannelid.php',1453226124,NULL),('phabricator:20130219.commitsummary.sql',1453226124,NULL),('phabricator:20130219.commitsummarymig.php',1453226124,NULL),('phabricator:20130222.dropchannel.sql',1453226124,NULL),('phabricator:20130226.commitkey.sql',1453226124,NULL),('phabricator:20130304.lintauthor.sql',1453226124,NULL),('phabricator:20130310.xactionmeta.sql',1453226124,NULL),('phabricator:20130317.phrictionedge.sql',1453226124,NULL),('phabricator:20130319.conpherence.sql',1453226124,NULL),('phabricator:20130319.phabricatorfileexplicitupload.sql',1453226124,NULL),('phabricator:20130320.phlux.sql',1453226124,NULL),('phabricator:20130321.token.sql',1453226124,NULL),('phabricator:20130322.phortune.sql',1453226124,NULL),('phabricator:20130323.phortunepayment.sql',1453226124,NULL),('phabricator:20130324.phortuneproduct.sql',1453226124,NULL),('phabricator:20130330.phrequent.sql',1453226124,NULL),('phabricator:20130403.conpherencecache.sql',1453226124,NULL),('phabricator:20130403.conpherencecachemig.php',1453226124,NULL),('phabricator:20130409.commitdrev.php',1453226124,NULL),('phabricator:20130417.externalaccount.sql',1453226124,NULL),('phabricator:20130423.conpherenceindices.sql',1453226125,NULL),('phabricator:20130423.phortunepaymentrevised.sql',1453226125,NULL),('phabricator:20130423.updateexternalaccount.sql',1453226124,NULL),('phabricator:20130426.search_savedquery.sql',1453226125,NULL),('phabricator:20130502.countdownrevamp1.sql',1453226125,NULL),('phabricator:20130502.countdownrevamp2.php',1453226125,NULL),('phabricator:20130502.countdownrevamp3.sql',1453226125,NULL),('phabricator:20130507.releephrqmailkey.sql',1453226125,NULL),('phabricator:20130507.releephrqmailkeypop.php',1453226125,NULL),('phabricator:20130507.releephrqsimplifycols.sql',1453226125,NULL),('phabricator:20130508.releephtransactions.sql',1453226125,NULL),('phabricator:20130508.releephtransactionsmig.php',1453226125,NULL),('phabricator:20130508.search_namedquery.sql',1453226125,NULL),('phabricator:20130513.receviedmailstatus.sql',1453226125,NULL),('phabricator:20130519.diviner.sql',1453226125,NULL),('phabricator:20130521.dropconphimages.sql',1453226125,NULL),('phabricator:20130523.maniphest_owners.sql',1453226125,NULL),('phabricator:20130524.repoxactions.sql',1453226125,NULL),('phabricator:20130529.macroauthor.sql',1453226125,NULL),('phabricator:20130529.macroauthormig.php',1453226125,NULL),('phabricator:20130530.macrodatekey.sql',1453226125,NULL),('phabricator:20130530.pastekeys.sql',1453226125,NULL),('phabricator:20130530.sessionhash.php',1453226125,NULL),('phabricator:20130531.filekeys.sql',1453226125,NULL),('phabricator:20130602.morediviner.sql',1453226125,NULL),('phabricator:20130602.namedqueries.sql',1453226125,NULL),('phabricator:20130606.userxactions.sql',1453226125,NULL),('phabricator:20130607.xaccount.sql',1453226125,NULL),('phabricator:20130611.migrateoauth.php',1453226125,NULL),('phabricator:20130611.nukeldap.php',1453226125,NULL),('phabricator:20130613.authdb.sql',1453226125,NULL),('phabricator:20130619.authconf.php',1453226125,NULL),('phabricator:20130620.diffxactions.sql',1453226125,NULL),('phabricator:20130621.diffcommentphid.sql',1453226125,NULL),('phabricator:20130621.diffcommentphidmig.php',1453226125,NULL),('phabricator:20130621.diffcommentunphid.sql',1453226125,NULL),('phabricator:20130622.doorkeeper.sql',1453226125,NULL),('phabricator:20130628.legalpadv0.sql',1453226125,NULL),('phabricator:20130701.conduitlog.sql',1453226125,NULL),('phabricator:20130703.legalpaddocdenorm.php',1453226125,NULL),('phabricator:20130703.legalpaddocdenorm.sql',1453226125,NULL),('phabricator:20130709.droptimeline.sql',1453226125,NULL),('phabricator:20130709.legalpadsignature.sql',1453226125,NULL),('phabricator:20130711.pholioimageobsolete.php',1453226126,NULL),('phabricator:20130711.pholioimageobsolete.sql',1453226126,NULL),('phabricator:20130711.pholioimageobsolete2.sql',1453226126,NULL),('phabricator:20130711.trimrealnames.php',1453226125,NULL),('phabricator:20130714.votexactions.sql',1453226125,NULL),('phabricator:20130715.votecomments.php',1453226125,NULL),('phabricator:20130715.voteedges.sql',1453226125,NULL),('phabricator:20130716.archivememberlessprojects.php',1453226126,NULL),('phabricator:20130722.pholioreplace.sql',1453226126,NULL),('phabricator:20130723.taskstarttime.sql',1453226126,NULL),('phabricator:20130726.ponderxactions.sql',1453226126,NULL),('phabricator:20130727.ponderquestionstatus.sql',1453226126,NULL),('phabricator:20130728.ponderunique.php',1453226126,NULL),('phabricator:20130728.ponderuniquekey.sql',1453226126,NULL),('phabricator:20130728.ponderxcomment.php',1453226126,NULL),('phabricator:20130731.releephcutpointidentifier.sql',1453226126,NULL),('phabricator:20130731.releephproject.sql',1453226126,NULL),('phabricator:20130731.releephrepoid.sql',1453226126,NULL),('phabricator:20130801.pastexactions.php',1453226126,NULL),('phabricator:20130801.pastexactions.sql',1453226126,NULL),('phabricator:20130802.heraldphid.sql',1453226126,NULL),('phabricator:20130802.heraldphids.php',1453226126,NULL),('phabricator:20130802.heraldphidukey.sql',1453226126,NULL),('phabricator:20130802.heraldxactions.sql',1453226126,NULL),('phabricator:20130805.pasteedges.sql',1453226126,NULL),('phabricator:20130805.pastemailkey.sql',1453226126,NULL),('phabricator:20130805.pastemailkeypop.php',1453226126,NULL),('phabricator:20130814.usercustom.sql',1453226126,NULL),('phabricator:20130820.file-mailkey-populate.php',1453226126,NULL),('phabricator:20130820.filemailkey.sql',1453226126,NULL),('phabricator:20130820.filexactions.sql',1453226126,NULL),('phabricator:20130820.releephxactions.sql',1453226126,NULL),('phabricator:20130826.divinernode.sql',1453226126,NULL),('phabricator:20130912.maniphest.1.touch.sql',1453226126,NULL),('phabricator:20130912.maniphest.2.created.sql',1453226126,NULL),('phabricator:20130912.maniphest.3.nameindex.sql',1453226126,NULL),('phabricator:20130912.maniphest.4.fillindex.php',1453226126,NULL),('phabricator:20130913.maniphest.1.migratesearch.php',1453226126,NULL),('phabricator:20130914.usercustom.sql',1453226126,NULL),('phabricator:20130915.maniphestcustom.sql',1453226126,NULL),('phabricator:20130915.maniphestmigrate.php',1453226126,NULL),('phabricator:20130915.maniphestqdrop.sql',1453226126,NULL),('phabricator:20130919.mfieldconf.php',1453226126,NULL),('phabricator:20130920.repokeyspolicy.sql',1453226126,NULL),('phabricator:20130921.mtransactions.sql',1453226126,NULL),('phabricator:20130921.xmigratemaniphest.php',1453226126,NULL),('phabricator:20130923.mrename.sql',1453226126,NULL),('phabricator:20130924.mdraftkey.sql',1453226126,NULL),('phabricator:20130925.mpolicy.sql',1453226126,NULL),('phabricator:20130925.xpolicy.sql',1453226126,NULL),('phabricator:20130926.dcustom.sql',1453226126,NULL),('phabricator:20130926.dinkeys.sql',1453226126,NULL),('phabricator:20130926.dinline.php',1453226126,NULL),('phabricator:20130927.audiomacro.sql',1453226126,NULL),('phabricator:20130929.filepolicy.sql',1453226126,NULL),('phabricator:20131004.dxedgekey.sql',1453226126,NULL),('phabricator:20131004.dxreviewers.php',1453226126,NULL),('phabricator:20131006.hdisable.sql',1453226126,NULL),('phabricator:20131010.pstorage.sql',1453226126,NULL),('phabricator:20131015.cpolicy.sql',1453226126,NULL),('phabricator:20131020.col1.sql',1453226126,NULL),('phabricator:20131020.harbormaster.sql',1453226126,NULL),('phabricator:20131020.pcustom.sql',1453226126,NULL),('phabricator:20131020.pxaction.sql',1453226126,NULL),('phabricator:20131020.pxactionmig.php',1453226126,NULL),('phabricator:20131025.repopush.sql',1453226127,NULL),('phabricator:20131026.commitstatus.sql',1453226127,NULL),('phabricator:20131030.repostatusmessage.sql',1453226127,NULL),('phabricator:20131031.vcspassword.sql',1453226127,NULL),('phabricator:20131105.buildstep.sql',1453226127,NULL),('phabricator:20131106.diffphid.1.col.sql',1453226127,NULL),('phabricator:20131106.diffphid.2.mig.php',1453226127,NULL),('phabricator:20131106.diffphid.3.key.sql',1453226127,NULL),('phabricator:20131106.nuance-v0.sql',1453226127,NULL),('phabricator:20131107.buildlog.sql',1453226127,NULL),('phabricator:20131112.userverified.1.col.sql',1453226127,NULL),('phabricator:20131112.userverified.2.mig.php',1453226127,NULL),('phabricator:20131118.ownerorder.php',1453226127,NULL),('phabricator:20131119.passphrase.sql',1453226127,NULL),('phabricator:20131120.nuancesourcetype.sql',1453226127,NULL),('phabricator:20131121.passphraseedge.sql',1453226127,NULL),('phabricator:20131121.repocredentials.1.col.sql',1453226127,NULL),('phabricator:20131121.repocredentials.2.mig.php',1453226127,NULL),('phabricator:20131122.repomirror.sql',1453226127,NULL),('phabricator:20131123.drydockblueprintpolicy.sql',1453226127,NULL),('phabricator:20131129.drydockresourceblueprint.sql',1453226127,NULL),('phabricator:20131204.pushlog.sql',1453226127,NULL),('phabricator:20131205.buildsteporder.sql',1453226127,NULL),('phabricator:20131205.buildstepordermig.php',1453226127,NULL),('phabricator:20131205.buildtargets.sql',1453226127,NULL),('phabricator:20131206.phragment.sql',1453226127,NULL),('phabricator:20131206.phragmentnull.sql',1453226127,NULL),('phabricator:20131208.phragmentsnapshot.sql',1453226127,NULL),('phabricator:20131211.phragmentedges.sql',1453226127,NULL),('phabricator:20131217.pushlogphid.1.col.sql',1453226127,NULL),('phabricator:20131217.pushlogphid.2.mig.php',1453226127,NULL),('phabricator:20131217.pushlogphid.3.key.sql',1453226127,NULL),('phabricator:20131219.pxdrop.sql',1453226127,NULL),('phabricator:20131224.harbormanual.sql',1453226127,NULL),('phabricator:20131227.heraldobject.sql',1453226127,NULL),('phabricator:20131231.dropshortcut.sql',1453226127,NULL),('phabricator:20131302.maniphestvalue.sql',1453226124,NULL),('phabricator:20140104.harbormastercmd.sql',1453226127,NULL),('phabricator:20140106.macromailkey.1.sql',1453226127,NULL),('phabricator:20140106.macromailkey.2.php',1453226127,NULL),('phabricator:20140108.ddbpname.1.sql',1453226127,NULL),('phabricator:20140108.ddbpname.2.php',1453226127,NULL),('phabricator:20140109.ddxactions.sql',1453226127,NULL),('phabricator:20140109.projectcolumnsdates.sql',1453226127,NULL),('phabricator:20140113.legalpadsig.1.sql',1453226127,NULL),('phabricator:20140113.legalpadsig.2.php',1453226127,NULL),('phabricator:20140115.auth.1.id.sql',1453226128,NULL),('phabricator:20140115.auth.2.expires.sql',1453226128,NULL),('phabricator:20140115.auth.3.unlimit.php',1453226128,NULL),('phabricator:20140115.legalpadsigkey.sql',1453226128,NULL),('phabricator:20140116.reporefcursor.sql',1453226128,NULL),('phabricator:20140126.diff.1.parentrevisionid.sql',1453226128,NULL),('phabricator:20140126.diff.2.repositoryphid.sql',1453226128,NULL),('phabricator:20140130.dash.1.board.sql',1453226128,NULL),('phabricator:20140130.dash.2.panel.sql',1453226128,NULL),('phabricator:20140130.dash.3.boardxaction.sql',1453226128,NULL),('phabricator:20140130.dash.4.panelxaction.sql',1453226128,NULL),('phabricator:20140130.mail.1.retry.sql',1453226128,NULL),('phabricator:20140130.mail.2.next.sql',1453226128,NULL),('phabricator:20140201.gc.1.mailsent.sql',1453226128,NULL),('phabricator:20140201.gc.2.mailreceived.sql',1453226128,NULL),('phabricator:20140205.cal.1.rename.sql',1453226128,NULL),('phabricator:20140205.cal.2.phid-col.sql',1453226128,NULL),('phabricator:20140205.cal.3.phid-mig.php',1453226128,NULL),('phabricator:20140205.cal.4.phid-key.sql',1453226128,NULL),('phabricator:20140210.herald.rule-condition-mig.php',1453226128,NULL),('phabricator:20140210.projcfield.1.blurb.php',1453226128,NULL),('phabricator:20140210.projcfield.2.piccol.sql',1453226128,NULL),('phabricator:20140210.projcfield.3.picmig.sql',1453226128,NULL),('phabricator:20140210.projcfield.4.memmig.sql',1453226128,NULL),('phabricator:20140210.projcfield.5.dropprofile.sql',1453226128,NULL),('phabricator:20140211.dx.1.nullablechangesetid.sql',1453226128,NULL),('phabricator:20140211.dx.2.migcommenttext.php',1453226128,NULL),('phabricator:20140211.dx.3.migsubscriptions.sql',1453226128,NULL),('phabricator:20140211.dx.999.drop.relationships.sql',1453226128,NULL),('phabricator:20140212.dx.1.armageddon.php',1453226128,NULL),('phabricator:20140214.clean.1.legacycommentid.sql',1453226128,NULL),('phabricator:20140214.clean.2.dropcomment.sql',1453226128,NULL),('phabricator:20140214.clean.3.dropinline.sql',1453226128,NULL),('phabricator:20140218.differentialdraft.sql',1453226128,NULL),('phabricator:20140218.passwords.1.extend.sql',1453226128,NULL),('phabricator:20140218.passwords.2.prefix.sql',1453226128,NULL),('phabricator:20140218.passwords.3.vcsextend.sql',1453226128,NULL),('phabricator:20140218.passwords.4.vcs.php',1453226128,NULL),('phabricator:20140223.bigutf8scratch.sql',1453226128,NULL),('phabricator:20140224.dxclean.1.datecommitted.sql',1453226128,NULL),('phabricator:20140226.dxcustom.1.fielddata.php',1453226128,NULL),('phabricator:20140226.dxcustom.99.drop.sql',1453226128,NULL),('phabricator:20140228.dxcomment.1.sql',1453226128,NULL),('phabricator:20140305.diviner.1.slugcol.sql',1453226128,NULL),('phabricator:20140305.diviner.2.slugkey.sql',1453226128,NULL),('phabricator:20140311.mdroplegacy.sql',1453226128,NULL),('phabricator:20140314.projectcolumn.1.statuscol.sql',1453226128,NULL),('phabricator:20140314.projectcolumn.2.statuskey.sql',1453226128,NULL),('phabricator:20140317.mupdatedkey.sql',1453226128,NULL),('phabricator:20140321.harbor.1.bxaction.sql',1453226128,NULL),('phabricator:20140321.mstatus.1.col.sql',1453226128,NULL),('phabricator:20140321.mstatus.2.mig.php',1453226128,NULL),('phabricator:20140323.harbor.1.renames.php',1453226128,NULL),('phabricator:20140323.harbor.2.message.sql',1453226128,NULL),('phabricator:20140325.push.1.event.sql',1453226128,NULL),('phabricator:20140325.push.2.eventphid.sql',1453226128,NULL),('phabricator:20140325.push.3.groups.php',1453226128,NULL),('phabricator:20140325.push.4.prune.sql',1453226128,NULL),('phabricator:20140326.project.1.colxaction.sql',1453226128,NULL),('phabricator:20140328.releeph.1.productxaction.sql',1453226128,NULL),('phabricator:20140330.flagtext.sql',1453226128,NULL),('phabricator:20140402.actionlog.sql',1453226128,NULL),('phabricator:20140410.accountsecret.1.sql',1453226128,NULL),('phabricator:20140410.accountsecret.2.php',1453226128,NULL),('phabricator:20140416.harbor.1.sql',1453226128,NULL),('phabricator:20140420.rel.1.objectphid.sql',1453226128,NULL),('phabricator:20140420.rel.2.objectmig.php',1453226128,NULL),('phabricator:20140421.slowvotecolumnsisclosed.sql',1453226128,NULL),('phabricator:20140423.session.1.hisec.sql',1453226128,NULL),('phabricator:20140427.mfactor.1.sql',1453226128,NULL),('phabricator:20140430.auth.1.partial.sql',1453226128,NULL),('phabricator:20140430.dash.1.paneltype.sql',1453226128,NULL),('phabricator:20140430.dash.2.edge.sql',1453226128,NULL),('phabricator:20140501.passphraselockcredential.sql',1453226128,NULL),('phabricator:20140501.remove.1.dlog.sql',1453226128,NULL),('phabricator:20140507.smstable.sql',1453226128,NULL),('phabricator:20140509.coverage.1.sql',1453226128,NULL),('phabricator:20140509.dashboardlayoutconfig.sql',1453226128,NULL),('phabricator:20140512.dparents.1.sql',1453226128,NULL),('phabricator:20140514.harbormasterbuildabletransaction.sql',1453226128,NULL),('phabricator:20140514.pholiomockclose.sql',1453226129,NULL),('phabricator:20140515.trust-emails.sql',1453226129,NULL),('phabricator:20140517.dxbinarycache.sql',1453226129,NULL),('phabricator:20140518.dxmorebinarycache.sql',1453226129,NULL),('phabricator:20140519.dashboardinstall.sql',1453226129,NULL),('phabricator:20140520.authtemptoken.sql',1453226129,NULL),('phabricator:20140521.projectslug.1.create.sql',1453226129,NULL),('phabricator:20140521.projectslug.2.mig.php',1453226129,NULL),('phabricator:20140522.projecticon.sql',1453226129,NULL),('phabricator:20140524.auth.mfa.cache.sql',1453226129,NULL),('phabricator:20140525.hunkmodern.sql',1453226129,NULL),('phabricator:20140615.pholioedit.1.sql',1453226129,NULL),('phabricator:20140615.pholioedit.2.sql',1453226129,NULL),('phabricator:20140617.daemon.explicit-argv.sql',1453226129,NULL),('phabricator:20140617.daemonlog.sql',1453226129,NULL),('phabricator:20140624.projcolor.1.sql',1453226129,NULL),('phabricator:20140624.projcolor.2.sql',1453226129,NULL),('phabricator:20140629.dasharchive.1.sql',1453226129,NULL),('phabricator:20140629.legalsig.1.sql',1453226129,NULL),('phabricator:20140629.legalsig.2.php',1453226129,NULL),('phabricator:20140701.legalexemption.1.sql',1453226129,NULL),('phabricator:20140701.legalexemption.2.sql',1453226129,NULL),('phabricator:20140703.legalcorp.1.sql',1453226129,NULL),('phabricator:20140703.legalcorp.2.sql',1453226129,NULL),('phabricator:20140703.legalcorp.3.sql',1453226129,NULL),('phabricator:20140703.legalcorp.4.sql',1453226129,NULL),('phabricator:20140703.legalcorp.5.sql',1453226129,NULL),('phabricator:20140704.harbormasterstep.1.sql',1453226129,NULL),('phabricator:20140704.harbormasterstep.2.sql',1453226129,NULL),('phabricator:20140704.legalpreamble.1.sql',1453226129,NULL),('phabricator:20140706.harbormasterdepend.1.php',1453226129,NULL),('phabricator:20140706.pedge.1.sql',1453226129,NULL),('phabricator:20140711.pnames.1.sql',1453226129,NULL),('phabricator:20140711.pnames.2.php',1453226129,NULL),('phabricator:20140711.workerpriority.sql',1453226129,NULL),('phabricator:20140712.projcoluniq.sql',1453226129,NULL),('phabricator:20140721.phortune.1.cart.sql',1453226129,NULL),('phabricator:20140721.phortune.2.purchase.sql',1453226129,NULL),('phabricator:20140721.phortune.3.charge.sql',1453226129,NULL),('phabricator:20140721.phortune.4.cartstatus.sql',1453226129,NULL),('phabricator:20140721.phortune.5.cstatusdefault.sql',1453226129,NULL),('phabricator:20140721.phortune.6.onetimecharge.sql',1453226129,NULL),('phabricator:20140721.phortune.7.nullmethod.sql',1453226129,NULL),('phabricator:20140722.appname.php',1453226129,NULL),('phabricator:20140722.audit.1.xactions.sql',1453226129,NULL),('phabricator:20140722.audit.2.comments.sql',1453226129,NULL),('phabricator:20140722.audit.3.miginlines.php',1453226129,NULL),('phabricator:20140722.audit.4.migtext.php',1453226129,NULL),('phabricator:20140722.renameauth.php',1453226129,NULL),('phabricator:20140723.apprenamexaction.sql',1453226129,NULL),('phabricator:20140725.audit.1.migxactions.php',1453226129,NULL),('phabricator:20140731.audit.1.subscribers.php',1453226129,NULL),('phabricator:20140731.cancdn.php',1453226129,NULL),('phabricator:20140731.harbormasterstepdesc.sql',1453226129,NULL),('phabricator:20140805.boardcol.1.sql',1453226129,NULL),('phabricator:20140805.boardcol.2.php',1453226129,NULL),('phabricator:20140807.harbormastertargettime.sql',1453226129,NULL),('phabricator:20140808.boardprop.1.sql',1453226129,NULL),('phabricator:20140808.boardprop.2.sql',1453226129,NULL),('phabricator:20140808.boardprop.3.php',1453226129,NULL),('phabricator:20140811.blob.1.sql',1453226129,NULL),('phabricator:20140811.blob.2.sql',1453226129,NULL),('phabricator:20140812.projkey.1.sql',1453226129,NULL),('phabricator:20140812.projkey.2.sql',1453226129,NULL),('phabricator:20140814.passphrasecredentialconduit.sql',1453226129,NULL),('phabricator:20140815.cancdncase.php',1453226129,NULL),('phabricator:20140818.harbormasterindex.1.sql',1453226129,NULL),('phabricator:20140821.harbormasterbuildgen.1.sql',1453226129,NULL),('phabricator:20140822.daemonenvhash.sql',1453226129,NULL),('phabricator:20140902.almanacdevice.1.sql',1453226129,NULL),('phabricator:20140904.macroattach.php',1453226129,NULL),('phabricator:20140911.fund.1.initiative.sql',1453226129,NULL),('phabricator:20140911.fund.2.xaction.sql',1453226129,NULL),('phabricator:20140911.fund.3.edge.sql',1453226129,NULL),('phabricator:20140911.fund.4.backer.sql',1453226129,NULL),('phabricator:20140911.fund.5.backxaction.sql',1453226129,NULL),('phabricator:20140914.betaproto.php',1453226129,NULL),('phabricator:20140917.project.canlock.sql',1453226129,NULL),('phabricator:20140918.schema.1.dropaudit.sql',1453226129,NULL),('phabricator:20140918.schema.2.dropauditinline.sql',1453226129,NULL),('phabricator:20140918.schema.3.wipecache.sql',1453226129,NULL),('phabricator:20140918.schema.4.cachetype.sql',1453226129,NULL),('phabricator:20140918.schema.5.slowvote.sql',1453226129,NULL),('phabricator:20140919.schema.01.calstatus.sql',1453226129,NULL),('phabricator:20140919.schema.02.calname.sql',1453226129,NULL),('phabricator:20140919.schema.03.dropaux.sql',1453226129,NULL),('phabricator:20140919.schema.04.droptaskproj.sql',1453226129,NULL),('phabricator:20140926.schema.01.droprelev.sql',1453226129,NULL),('phabricator:20140926.schema.02.droprelreqev.sql',1453226129,NULL),('phabricator:20140926.schema.03.dropldapinfo.sql',1453226129,NULL),('phabricator:20140926.schema.04.dropoauthinfo.sql',1453226129,NULL),('phabricator:20140926.schema.05.dropprojaffil.sql',1453226129,NULL),('phabricator:20140926.schema.06.dropsubproject.sql',1453226129,NULL),('phabricator:20140926.schema.07.droppondcom.sql',1453226129,NULL),('phabricator:20140927.schema.01.dropsearchq.sql',1453226129,NULL),('phabricator:20140927.schema.02.pholio1.sql',1453226129,NULL),('phabricator:20140927.schema.03.pholio2.sql',1453226129,NULL),('phabricator:20140927.schema.04.pholio3.sql',1453226129,NULL),('phabricator:20140927.schema.05.phragment1.sql',1453226130,NULL),('phabricator:20140927.schema.06.releeph1.sql',1453226130,NULL),('phabricator:20141001.schema.01.version.sql',1453226130,NULL),('phabricator:20141001.schema.02.taskmail.sql',1453226130,NULL),('phabricator:20141002.schema.01.liskcounter.sql',1453226130,NULL),('phabricator:20141002.schema.02.draftnull.sql',1453226130,NULL),('phabricator:20141004.currency.01.sql',1453226130,NULL),('phabricator:20141004.currency.02.sql',1453226130,NULL),('phabricator:20141004.currency.03.sql',1453226130,NULL),('phabricator:20141004.currency.04.sql',1453226130,NULL),('phabricator:20141004.currency.05.sql',1453226130,NULL),('phabricator:20141004.currency.06.sql',1453226130,NULL),('phabricator:20141004.harborliskcounter.sql',1453226130,NULL),('phabricator:20141005.phortuneproduct.sql',1453226130,NULL),('phabricator:20141006.phortunecart.sql',1453226130,NULL),('phabricator:20141006.phortunemerchant.sql',1453226130,NULL),('phabricator:20141006.phortunemerchantx.sql',1453226130,NULL),('phabricator:20141007.fundmerchant.sql',1453226130,NULL),('phabricator:20141007.fundrisks.sql',1453226130,NULL),('phabricator:20141007.fundtotal.sql',1453226130,NULL),('phabricator:20141007.phortunecartmerchant.sql',1453226130,NULL),('phabricator:20141007.phortunecharge.sql',1453226130,NULL),('phabricator:20141007.phortunepayment.sql',1453226130,NULL),('phabricator:20141007.phortuneprovider.sql',1453226130,NULL),('phabricator:20141007.phortuneproviderx.sql',1453226130,NULL),('phabricator:20141008.phortunemerchdesc.sql',1453226130,NULL),('phabricator:20141008.phortuneprovdis.sql',1453226130,NULL),('phabricator:20141008.phortunerefund.sql',1453226130,NULL),('phabricator:20141010.fundmailkey.sql',1453226130,NULL),('phabricator:20141011.phortunemerchedit.sql',1453226130,NULL),('phabricator:20141012.phortunecartxaction.sql',1453226130,NULL),('phabricator:20141013.phortunecartkey.sql',1453226130,NULL),('phabricator:20141016.almanac.device.sql',1453226130,NULL),('phabricator:20141016.almanac.dxaction.sql',1453226130,NULL),('phabricator:20141016.almanac.interface.sql',1453226130,NULL),('phabricator:20141016.almanac.network.sql',1453226130,NULL),('phabricator:20141016.almanac.nxaction.sql',1453226130,NULL),('phabricator:20141016.almanac.service.sql',1453226130,NULL),('phabricator:20141016.almanac.sxaction.sql',1453226130,NULL),('phabricator:20141017.almanac.binding.sql',1453226130,NULL),('phabricator:20141017.almanac.bxaction.sql',1453226130,NULL),('phabricator:20141025.phriction.1.xaction.sql',1453226130,NULL),('phabricator:20141025.phriction.2.xaction.sql',1453226130,NULL),('phabricator:20141025.phriction.mailkey.sql',1453226130,NULL),('phabricator:20141103.almanac.1.delprop.sql',1453226130,NULL),('phabricator:20141103.almanac.2.addprop.sql',1453226131,NULL),('phabricator:20141104.almanac.3.edge.sql',1453226131,NULL),('phabricator:20141105.ssh.1.rename.sql',1453226131,NULL),('phabricator:20141106.dropold.sql',1453226131,NULL),('phabricator:20141106.uniqdrafts.php',1453226131,NULL),('phabricator:20141107.phriction.policy.1.sql',1453226131,NULL),('phabricator:20141107.phriction.policy.2.php',1453226131,NULL),('phabricator:20141107.phriction.popkeys.php',1453226131,NULL),('phabricator:20141107.ssh.1.colname.sql',1453226131,NULL),('phabricator:20141107.ssh.2.keyhash.sql',1453226131,NULL),('phabricator:20141107.ssh.3.keyindex.sql',1453226131,NULL),('phabricator:20141107.ssh.4.keymig.php',1453226131,NULL),('phabricator:20141107.ssh.5.indexnull.sql',1453226131,NULL),('phabricator:20141107.ssh.6.indexkey.sql',1453226131,NULL),('phabricator:20141107.ssh.7.colnull.sql',1453226131,NULL),('phabricator:20141113.auditdupes.php',1453226131,NULL),('phabricator:20141118.diffxaction.sql',1453226131,NULL),('phabricator:20141119.commitpedge.sql',1453226131,NULL),('phabricator:20141119.differential.diff.policy.sql',1453226131,NULL),('phabricator:20141119.sshtrust.sql',1453226131,NULL),('phabricator:20141123.taskpriority.1.sql',1453226131,NULL),('phabricator:20141123.taskpriority.2.sql',1453226131,NULL),('phabricator:20141210.maniphestsubscribersmig.1.sql',1453226131,NULL),('phabricator:20141210.maniphestsubscribersmig.2.sql',1453226131,NULL),('phabricator:20141210.reposervice.sql',1453226131,NULL),('phabricator:20141212.conduittoken.sql',1453226131,NULL),('phabricator:20141215.almanacservicetype.sql',1453226131,NULL),('phabricator:20141217.almanacdevicelock.sql',1453226131,NULL),('phabricator:20141217.almanaclock.sql',1453226131,NULL),('phabricator:20141218.maniphestcctxn.php',1453226131,NULL),('phabricator:20141222.maniphestprojtxn.php',1453226131,NULL),('phabricator:20141223.daemonloguser.sql',1453226131,NULL),('phabricator:20141223.daemonobjectphid.sql',1453226131,NULL),('phabricator:20141230.pasteeditpolicycolumn.sql',1453226131,NULL),('phabricator:20141230.pasteeditpolicyexisting.sql',1453226131,NULL),('phabricator:20150102.policyname.php',1453226131,NULL),('phabricator:20150102.tasksubscriber.sql',1453226131,NULL),('phabricator:20150105.conpsearch.sql',1453226131,NULL),('phabricator:20150114.oauthserver.client.policy.sql',1453226131,NULL),('phabricator:20150115.applicationemails.sql',1453226131,NULL),('phabricator:20150115.trigger.1.sql',1453226131,NULL),('phabricator:20150115.trigger.2.sql',1453226131,NULL),('phabricator:20150116.maniphestapplicationemails.php',1453226131,NULL),('phabricator:20150120.maniphestdefaultauthor.php',1453226131,NULL),('phabricator:20150124.subs.1.sql',1453226131,NULL),('phabricator:20150129.pastefileapplicationemails.php',1453226131,NULL),('phabricator:20150130.phortune.1.subphid.sql',1453226131,NULL),('phabricator:20150130.phortune.2.subkey.sql',1453226131,NULL),('phabricator:20150131.phortune.1.defaultpayment.sql',1453226131,NULL),('phabricator:20150205.authprovider.autologin.sql',1453226131,NULL),('phabricator:20150205.daemonenv.sql',1453226131,NULL),('phabricator:20150209.invite.sql',1453226131,NULL),('phabricator:20150209.oauthclient.trust.sql',1453226131,NULL),('phabricator:20150210.invitephid.sql',1453226131,NULL),('phabricator:20150212.legalpad.session.1.sql',1453226131,NULL),('phabricator:20150212.legalpad.session.2.sql',1453226131,NULL),('phabricator:20150219.scratch.nonmutable.sql',1453226131,NULL),('phabricator:20150223.daemon.1.id.sql',1453226131,NULL),('phabricator:20150223.daemon.2.idlegacy.sql',1453226131,NULL),('phabricator:20150223.daemon.3.idkey.sql',1453226131,NULL),('phabricator:20150312.filechunk.1.sql',1453226131,NULL),('phabricator:20150312.filechunk.2.sql',1453226131,NULL),('phabricator:20150312.filechunk.3.sql',1453226131,NULL),('phabricator:20150317.conpherence.isroom.1.sql',1453226131,NULL),('phabricator:20150317.conpherence.isroom.2.sql',1453226131,NULL),('phabricator:20150317.conpherence.policy.sql',1453226131,NULL),('phabricator:20150410.nukeruleedit.sql',1453226131,NULL),('phabricator:20150420.invoice.1.sql',1453226131,NULL),('phabricator:20150420.invoice.2.sql',1453226131,NULL),('phabricator:20150425.isclosed.sql',1453226131,NULL),('phabricator:20150427.calendar.1.edge.sql',1453226131,NULL),('phabricator:20150427.calendar.1.xaction.sql',1453226131,NULL),('phabricator:20150427.calendar.2.xaction.sql',1453226131,NULL),('phabricator:20150428.calendar.1.iscancelled.sql',1453226131,NULL),('phabricator:20150428.calendar.1.name.sql',1453226131,NULL),('phabricator:20150429.calendar.1.invitee.sql',1453226131,NULL),('phabricator:20150430.calendar.1.policies.sql',1453226132,NULL),('phabricator:20150430.multimeter.1.sql',1453226132,NULL),('phabricator:20150430.multimeter.2.host.sql',1453226132,NULL),('phabricator:20150430.multimeter.3.viewer.sql',1453226132,NULL),('phabricator:20150430.multimeter.4.context.sql',1453226132,NULL),('phabricator:20150430.multimeter.5.label.sql',1453226132,NULL),('phabricator:20150501.calendar.1.reply.sql',1453226132,NULL),('phabricator:20150501.calendar.2.reply.php',1453226132,NULL),('phabricator:20150501.conpherencepics.sql',1453226132,NULL),('phabricator:20150503.repositorysymbols.1.sql',1453226132,NULL),('phabricator:20150503.repositorysymbols.2.php',1453226132,NULL),('phabricator:20150503.repositorysymbols.3.sql',1453226132,NULL),('phabricator:20150504.symbolsproject.1.php',1453226132,NULL),('phabricator:20150504.symbolsproject.2.sql',1453226132,NULL),('phabricator:20150506.calendarunnamedevents.1.php',1453226132,NULL),('phabricator:20150507.calendar.1.isallday.sql',1453226132,NULL),('phabricator:20150513.user.cache.1.sql',1453226132,NULL),('phabricator:20150514.calendar.status.sql',1453226132,NULL),('phabricator:20150514.phame.blog.xaction.sql',1453226132,NULL),('phabricator:20150514.user.cache.2.sql',1453226132,NULL),('phabricator:20150515.phame.post.xaction.sql',1453226132,NULL),('phabricator:20150515.project.mailkey.1.sql',1453226132,NULL),('phabricator:20150515.project.mailkey.2.php',1453226132,NULL),('phabricator:20150519.calendar.calendaricon.sql',1453226132,NULL),('phabricator:20150521.releephrepository.sql',1453226132,NULL),('phabricator:20150525.diff.hidden.1.sql',1453226132,NULL),('phabricator:20150526.owners.mailkey.1.sql',1453226132,NULL),('phabricator:20150526.owners.mailkey.2.php',1453226132,NULL),('phabricator:20150526.owners.xaction.sql',1453226132,NULL),('phabricator:20150527.calendar.recurringevents.sql',1453226132,NULL),('phabricator:20150601.spaces.1.namespace.sql',1453226132,NULL),('phabricator:20150601.spaces.2.xaction.sql',1453226132,NULL),('phabricator:20150602.mlist.1.sql',1453226132,NULL),('phabricator:20150602.mlist.2.php',1453226132,NULL),('phabricator:20150604.spaces.1.sql',1453226132,NULL),('phabricator:20150605.diviner.edges.sql',1453226132,NULL),('phabricator:20150605.diviner.editPolicy.sql',1453226132,NULL),('phabricator:20150605.diviner.xaction.sql',1453226132,NULL),('phabricator:20150606.mlist.1.php',1453226132,NULL),('phabricator:20150609.inline.sql',1453226132,NULL),('phabricator:20150609.spaces.1.pholio.sql',1453226132,NULL),('phabricator:20150609.spaces.2.maniphest.sql',1453226132,NULL),('phabricator:20150610.spaces.1.desc.sql',1453226132,NULL),('phabricator:20150610.spaces.2.edge.sql',1453226132,NULL),('phabricator:20150610.spaces.3.archive.sql',1453226132,NULL),('phabricator:20150611.spaces.1.mailxaction.sql',1453226132,NULL),('phabricator:20150611.spaces.2.appmail.sql',1453226132,NULL),('phabricator:20150616.divinerrepository.sql',1453226132,NULL),('phabricator:20150617.harbor.1.lint.sql',1453226132,NULL),('phabricator:20150617.harbor.2.unit.sql',1453226132,NULL),('phabricator:20150618.harbor.1.planauto.sql',1453226132,NULL),('phabricator:20150618.harbor.2.stepauto.sql',1453226132,NULL),('phabricator:20150618.harbor.3.buildauto.sql',1453226132,NULL),('phabricator:20150619.conpherencerooms.1.sql',1453226132,NULL),('phabricator:20150619.conpherencerooms.2.sql',1453226132,NULL),('phabricator:20150619.conpherencerooms.3.sql',1453226132,NULL),('phabricator:20150621.phrase.1.sql',1453226132,NULL),('phabricator:20150621.phrase.2.sql',1453226132,NULL),('phabricator:20150622.bulk.1.job.sql',1453226132,NULL),('phabricator:20150622.bulk.2.task.sql',1453226132,NULL),('phabricator:20150622.bulk.3.xaction.sql',1453226132,NULL),('phabricator:20150622.bulk.4.edge.sql',1453226132,NULL),('phabricator:20150622.metamta.1.phid-col.sql',1453226132,NULL),('phabricator:20150622.metamta.2.phid-mig.php',1453226132,NULL),('phabricator:20150622.metamta.3.phid-key.sql',1453226132,NULL),('phabricator:20150622.metamta.4.actor-phid-col.sql',1453226132,NULL),('phabricator:20150622.metamta.5.actor-phid-mig.php',1453226132,NULL),('phabricator:20150622.metamta.6.actor-phid-key.sql',1453226132,NULL),('phabricator:20150624.spaces.1.repo.sql',1453226132,NULL),('phabricator:20150626.spaces.1.calendar.sql',1453226132,NULL),('phabricator:20150630.herald.1.sql',1453226132,NULL),('phabricator:20150630.herald.2.sql',1453226132,NULL),('phabricator:20150701.herald.1.sql',1453226132,NULL),('phabricator:20150701.herald.2.sql',1453226132,NULL),('phabricator:20150702.spaces.1.slowvote.sql',1453226133,NULL),('phabricator:20150706.herald.1.sql',1453226133,NULL),('phabricator:20150707.herald.1.sql',1453226133,NULL),('phabricator:20150708.arcanistproject.sql',1453226133,NULL),('phabricator:20150708.herald.1.sql',1453226133,NULL),('phabricator:20150708.herald.2.sql',1453226133,NULL),('phabricator:20150708.herald.3.sql',1453226133,NULL),('phabricator:20150712.badges.1.sql',1453226133,NULL),('phabricator:20150714.spaces.countdown.1.sql',1453226133,NULL),('phabricator:20150717.herald.1.sql',1453226133,NULL),('phabricator:20150719.countdown.1.sql',1453226133,NULL),('phabricator:20150719.countdown.2.sql',1453226133,NULL),('phabricator:20150719.countdown.3.sql',1453226133,NULL),('phabricator:20150721.phurl.1.url.sql',1453226133,NULL),('phabricator:20150721.phurl.2.xaction.sql',1453226133,NULL),('phabricator:20150721.phurl.3.xactioncomment.sql',1453226133,NULL),('phabricator:20150721.phurl.4.url.sql',1453226133,NULL),('phabricator:20150721.phurl.5.edge.sql',1453226133,NULL),('phabricator:20150721.phurl.6.alias.sql',1453226133,NULL),('phabricator:20150721.phurl.7.authorphid.sql',1453226133,NULL),('phabricator:20150722.dashboard.1.sql',1453226133,NULL),('phabricator:20150722.dashboard.2.sql',1453226133,NULL),('phabricator:20150723.countdown.1.sql',1453226133,NULL),('phabricator:20150724.badges.comments.1.sql',1453226133,NULL),('phabricator:20150724.countdown.comments.1.sql',1453226133,NULL),('phabricator:20150725.badges.mailkey.1.sql',1453226133,NULL),('phabricator:20150725.badges.mailkey.2.php',1453226133,NULL),('phabricator:20150725.badges.viewpolicy.3.sql',1453226133,NULL),('phabricator:20150725.countdown.mailkey.1.sql',1453226133,NULL),('phabricator:20150725.countdown.mailkey.2.php',1453226133,NULL),('phabricator:20150725.slowvote.mailkey.1.sql',1453226133,NULL),('phabricator:20150725.slowvote.mailkey.2.php',1453226133,NULL),('phabricator:20150727.heraldaction.1.sql',1453226133,NULL),('phabricator:20150730.herald.1.sql',1453226133,NULL),('phabricator:20150730.herald.2.sql',1453226133,NULL),('phabricator:20150730.herald.3.sql',1453226133,NULL),('phabricator:20150730.herald.4.sql',1453226133,NULL),('phabricator:20150730.herald.5.sql',1453226133,NULL),('phabricator:20150730.herald.6.sql',1453226133,NULL),('phabricator:20150730.herald.7.sql',1453226133,NULL),('phabricator:20150803.herald.1.sql',1453226133,NULL),('phabricator:20150803.herald.2.sql',1453226133,NULL),('phabricator:20150804.ponder.answer.mailkey.1.sql',1453226133,NULL),('phabricator:20150804.ponder.answer.mailkey.2.php',1453226133,NULL),('phabricator:20150804.ponder.question.1.sql',1453226133,NULL),('phabricator:20150804.ponder.question.2.sql',1453226133,NULL),('phabricator:20150804.ponder.question.3.sql',1453226133,NULL),('phabricator:20150804.ponder.spaces.4.sql',1453226133,NULL),('phabricator:20150805.paste.status.1.sql',1453226133,NULL),('phabricator:20150805.paste.status.2.sql',1453226133,NULL),('phabricator:20150806.ponder.answer.1.sql',1453226133,NULL),('phabricator:20150806.ponder.editpolicy.2.sql',1453226133,NULL),('phabricator:20150806.ponder.status.1.sql',1453226133,NULL),('phabricator:20150806.ponder.status.2.sql',1453226133,NULL),('phabricator:20150806.ponder.status.3.sql',1453226133,NULL),('phabricator:20150808.ponder.vote.1.sql',1453226133,NULL),('phabricator:20150808.ponder.vote.2.sql',1453226133,NULL),('phabricator:20150812.ponder.answer.1.sql',1453226133,NULL),('phabricator:20150812.ponder.answer.2.sql',1453226133,NULL),('phabricator:20150814.harbormater.artifact.phid.sql',1453226133,NULL),('phabricator:20150815.owners.status.1.sql',1453226133,NULL),('phabricator:20150815.owners.status.2.sql',1453226133,NULL),('phabricator:20150823.nuance.queue.1.sql',1453226133,NULL),('phabricator:20150823.nuance.queue.2.sql',1453226133,NULL),('phabricator:20150823.nuance.queue.3.sql',1453226133,NULL),('phabricator:20150823.nuance.queue.4.sql',1453226133,NULL),('phabricator:20150828.ponder.wiki.1.sql',1453226133,NULL),('phabricator:20150829.ponder.dupe.1.sql',1453226133,NULL),('phabricator:20150904.herald.1.sql',1453226133,NULL),('phabricator:20150906.mailinglist.sql',1453226133,NULL),('phabricator:20150910.owners.custom.1.sql',1453226133,NULL),('phabricator:20150916.drydock.slotlocks.1.sql',1453226133,NULL),('phabricator:20150922.drydock.commands.1.sql',1453226133,NULL),('phabricator:20150923.drydock.resourceid.1.sql',1453226133,NULL),('phabricator:20150923.drydock.resourceid.2.sql',1453226133,NULL),('phabricator:20150923.drydock.resourceid.3.sql',1453226133,NULL),('phabricator:20150923.drydock.taskid.1.sql',1453226133,NULL),('phabricator:20150924.drydock.disable.1.sql',1453226133,NULL),('phabricator:20150924.drydock.status.1.sql',1453226133,NULL),('phabricator:20150928.drydock.rexpire.1.sql',1453226133,NULL),('phabricator:20150930.drydock.log.1.sql',1453226134,NULL),('phabricator:20151001.drydock.rname.1.sql',1453226134,NULL),('phabricator:20151002.dashboard.status.1.sql',1453226134,NULL),('phabricator:20151002.harbormaster.bparam.1.sql',1453226134,NULL),('phabricator:20151009.drydock.auth.1.sql',1453226134,NULL),('phabricator:20151010.drydock.auth.2.sql',1453226134,NULL),('phabricator:20151013.drydock.op.1.sql',1453226134,NULL),('phabricator:20151023.harborpolicy.1.sql',1453226134,NULL),('phabricator:20151023.harborpolicy.2.php',1453226134,NULL),('phabricator:20151023.patchduration.sql',1453226134,14142),('phabricator:20151030.harbormaster.initiator.sql',1453226134,35726),('phabricator:20151106.editengine.1.table.sql',1453226134,8030),('phabricator:20151106.editengine.2.xactions.sql',1453226134,7392),('phabricator:20151106.phame.post.mailkey.1.sql',1453226134,18595),('phabricator:20151106.phame.post.mailkey.2.php',1453226134,1616),('phabricator:20151107.phame.blog.mailkey.1.sql',1453226134,19832),('phabricator:20151107.phame.blog.mailkey.2.php',1453226134,1389),('phabricator:20151108.phame.blog.joinpolicy.sql',1453226134,16415),('phabricator:20151108.xhpast.stderr.sql',1453226134,24424),('phabricator:20151109.phame.post.comments.1.sql',1453226134,8007),('phabricator:20151109.repository.coverage.1.sql',1453226134,1405),('phabricator:20151109.xhpast.db.1.sql',1453226134,1559),('phabricator:20151109.xhpast.db.2.sql',1453226134,599),('phabricator:20151110.daemonenvhash.sql',1453226134,39904),('phabricator:20151111.phame.blog.archive.1.sql',1453226134,15720),('phabricator:20151111.phame.blog.archive.2.sql',1453226134,534),('phabricator:20151112.herald.edge.sql',1453226134,13618),('phabricator:20151116.owners.edge.sql',1453226134,13570),('phabricator:20151128.phame.blog.picture.1.sql',1453226134,15964),('phabricator:20151130.phurl.mailkey.1.sql',1453226134,10402),('phabricator:20151130.phurl.mailkey.2.php',1453226134,1457),('phabricator:20151202.versioneddraft.1.sql',1453226134,8923),('phabricator:20151207.editengine.1.sql',1453226134,76111),('phabricator:20151210.land.1.refphid.sql',1453226134,19463),('phabricator:20151210.land.2.refphid.php',1453226134,833),('phabricator:20151215.phame.1.autotitle.sql',1453226134,21510),('phabricator:20151218.key.1.keyphid.sql',1453226134,14834),('phabricator:20151218.key.2.keyphid.php',1453226134,429),('phabricator:20151219.proj.01.prislug.sql',1453226134,21059),('phabricator:20151219.proj.02.prislugkey.sql',1453226134,16233),('phabricator:20151219.proj.03.copyslug.sql',1453226134,474),('phabricator:20151219.proj.04.dropslugkey.sql',1453226134,7782),('phabricator:20151219.proj.05.dropslug.sql',1453226134,20865),('phabricator:20151219.proj.06.defaultpolicy.php',1453226134,1358),('phabricator:20151219.proj.07.viewnull.sql',1453226134,16753),('phabricator:20151219.proj.08.editnull.sql',1453226134,13683),('phabricator:20151219.proj.09.joinnull.sql',1453226134,10924),('phabricator:20151219.proj.10.subcolumns.sql',1453226134,129879),('phabricator:20151219.proj.11.subprojectphids.sql',1453226135,26586),('phabricator:20151221.search.1.version.sql',1453226135,14029),('phabricator:20151221.search.2.ownersngrams.sql',1453226135,7390),('phabricator:20151221.search.3.reindex.php',1453226135,436),('phabricator:20151223.proj.01.paths.sql',1453226135,22387),('phabricator:20151223.proj.02.depths.sql',1453226135,28069),('phabricator:20151223.proj.03.pathkey.sql',1453226135,12562),('phabricator:20151223.proj.04.keycol.sql',1453226135,24719),('phabricator:20151223.proj.05.updatekeys.php',1453226135,463),('phabricator:20151223.proj.06.uniq.sql',1453226135,12857),('phabricator:20151226.reop.1.sql',1453226135,19351),('phabricator:20151227.proj.01.materialize.sql',1453226135,697),('phabricator:20151231.proj.01.icon.php',1453226135,3273),('phabricator:20160110.repo.01.slug.sql',1453226135,31556),('phabricator:20160110.repo.02.slug.php',1453226135,461),('phabricator:20160111.repo.01.slugx.sql',1453226135,745),('phabricator:20160112.repo.01.uri.sql',1453226135,7698),('phabricator:20160112.repo.02.uri.index.php',1453226135,437),('phabricator:20160113.propanel.1.storage.sql',1453226135,6273),('phabricator:20160113.propanel.2.xaction.sql',1453226135,7608),('phabricator:daemonstatus.sql',1453226123,NULL),('phabricator:daemonstatuskey.sql',1453226123,NULL),('phabricator:daemontaskarchive.sql',1453226124,NULL),('phabricator:db.almanac',1453226117,NULL),('phabricator:db.audit',1453226117,NULL),('phabricator:db.auth',1453226117,NULL),('phabricator:db.badges',1453226117,NULL),('phabricator:db.cache',1453226117,NULL),('phabricator:db.calendar',1453226117,NULL),('phabricator:db.chatlog',1453226117,NULL),('phabricator:db.conduit',1453226117,NULL),('phabricator:db.config',1453226117,NULL),('phabricator:db.conpherence',1453226117,NULL),('phabricator:db.countdown',1453226117,NULL),('phabricator:db.daemon',1453226117,NULL),('phabricator:db.dashboard',1453226117,NULL),('phabricator:db.differential',1453226117,NULL),('phabricator:db.diviner',1453226117,NULL),('phabricator:db.doorkeeper',1453226117,NULL),('phabricator:db.draft',1453226117,NULL),('phabricator:db.drydock',1453226117,NULL),('phabricator:db.fact',1453226117,NULL),('phabricator:db.feed',1453226117,NULL),('phabricator:db.file',1453226117,NULL),('phabricator:db.flag',1453226117,NULL),('phabricator:db.fund',1453226117,NULL),('phabricator:db.harbormaster',1453226117,NULL),('phabricator:db.herald',1453226117,NULL),('phabricator:db.legalpad',1453226117,NULL),('phabricator:db.maniphest',1453226117,NULL),('phabricator:db.meta_data',1453226117,NULL),('phabricator:db.metamta',1453226117,NULL),('phabricator:db.multimeter',1453226117,NULL),('phabricator:db.nuance',1453226117,NULL),('phabricator:db.oauth_server',1453226117,NULL),('phabricator:db.owners',1453226117,NULL),('phabricator:db.passphrase',1453226117,NULL),('phabricator:db.pastebin',1453226117,NULL),('phabricator:db.phame',1453226117,NULL),('phabricator:db.phlux',1453226117,NULL),('phabricator:db.pholio',1453226117,NULL),('phabricator:db.phortune',1453226117,NULL),('phabricator:db.phragment',1453226117,NULL),('phabricator:db.phrequent',1453226117,NULL),('phabricator:db.phriction',1453226117,NULL),('phabricator:db.phurl',1453226117,NULL),('phabricator:db.policy',1453226117,NULL),('phabricator:db.ponder',1453226117,NULL),('phabricator:db.project',1453226117,NULL),('phabricator:db.releeph',1453226117,NULL),('phabricator:db.repository',1453226117,NULL),('phabricator:db.search',1453226117,NULL),('phabricator:db.slowvote',1453226117,NULL),('phabricator:db.spaces',1453226117,NULL),('phabricator:db.system',1453226117,NULL),('phabricator:db.timeline',1453226117,NULL),('phabricator:db.token',1453226117,NULL),('phabricator:db.user',1453226117,NULL),('phabricator:db.worker',1453226117,NULL),('phabricator:db.xhpast',1453226117,NULL),('phabricator:db.xhpastview',1453226117,NULL),('phabricator:db.xhprof',1453226117,NULL),('phabricator:differentialbookmarks.sql',1453226123,NULL),('phabricator:draft-metadata.sql',1453226123,NULL),('phabricator:dropfileproxyimage.sql',1453226124,NULL),('phabricator:drydockresoucetype.sql',1453226124,NULL),('phabricator:drydocktaskid.sql',1453226124,NULL),('phabricator:edgetype.sql',1453226123,NULL),('phabricator:emailtable.sql',1453226123,NULL),('phabricator:emailtableport.sql',1453226123,NULL),('phabricator:emailtableremove.sql',1453226123,NULL),('phabricator:fact-raw.sql',1453226123,NULL),('phabricator:harbormasterobject.sql',1453226123,NULL),('phabricator:holidays.sql',1453226123,NULL),('phabricator:ldapinfo.sql',1453226123,NULL),('phabricator:legalpad-mailkey-populate.php',1453226125,NULL),('phabricator:legalpad-mailkey.sql',1453226125,NULL),('phabricator:liskcounters-task.sql',1453226124,NULL),('phabricator:liskcounters.php',1453226124,NULL),('phabricator:liskcounters.sql',1453226124,NULL),('phabricator:maniphestxcache.sql',1453226123,NULL),('phabricator:markupcache.sql',1453226123,NULL),('phabricator:migrate-differential-dependencies.php',1453226123,NULL),('phabricator:migrate-maniphest-dependencies.php',1453226123,NULL),('phabricator:migrate-maniphest-revisions.php',1453226123,NULL),('phabricator:migrate-project-edges.php',1453226123,NULL),('phabricator:owners-exclude.sql',1453226124,NULL),('phabricator:pastepolicy.sql',1453226123,NULL),('phabricator:phameblog.sql',1453226123,NULL),('phabricator:phamedomain.sql',1453226123,NULL),('phabricator:phameoneblog.sql',1453226123,NULL),('phabricator:phamepolicy.sql',1453226123,NULL),('phabricator:phiddrop.sql',1453226123,NULL),('phabricator:pholio.sql',1453226124,NULL),('phabricator:policy-project.sql',1453226123,NULL),('phabricator:ponder-comments.sql',1453226123,NULL),('phabricator:ponder-mailkey-populate.php',1453226123,NULL),('phabricator:ponder-mailkey.sql',1453226123,NULL),('phabricator:ponder.sql',1453226123,NULL),('phabricator:releeph.sql',1453226124,NULL),('phabricator:repository-lint.sql',1453226124,NULL),('phabricator:statustxt.sql',1453226124,NULL),('phabricator:symbolcontexts.sql',1453226123,NULL),('phabricator:testdatabase.sql',1453226123,NULL),('phabricator:threadtopic.sql',1453226123,NULL),('phabricator:userstatus.sql',1453226123,NULL),('phabricator:usertranslation.sql',1453226123,NULL),('phabricator:xhprof.sql',1453226123,NULL); CREATE DATABASE /*!32312 IF NOT EXISTS*/ `{$NAMESPACE}_metamta` /*!40100 DEFAULT CHARACTER SET {$CHARSET} COLLATE {$COLLATE_TEXT} */; @@ -1665,20 +1736,6 @@ CREATE TABLE `metamta_mail` ( KEY `status` (`status`) ) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE={$COLLATE_TEXT}; -CREATE TABLE `metamta_mailinglist` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `phid` varbinary(64) NOT NULL, - `name` varchar(128) COLLATE {$COLLATE_TEXT} NOT NULL, - `email` varchar(128) COLLATE {$COLLATE_TEXT} NOT NULL, - `uri` varchar(255) COLLATE {$COLLATE_TEXT} DEFAULT NULL, - `dateCreated` int(10) unsigned NOT NULL, - `dateModified` int(10) unsigned NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `phid` (`phid`), - UNIQUE KEY `email` (`email`), - UNIQUE KEY `name` (`name`) -) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE={$COLLATE_TEXT}; - CREATE TABLE `metamta_receivedmail` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `headers` longtext COLLATE {$COLLATE_TEXT} NOT NULL, @@ -1774,6 +1831,24 @@ CREATE DATABASE /*!32312 IF NOT EXISTS*/ `{$NAMESPACE}_owners` /*!40100 DEFAULT USE `{$NAMESPACE}_owners`; +CREATE TABLE `edge` ( + `src` varbinary(64) NOT NULL, + `type` int(10) unsigned NOT NULL, + `dst` varbinary(64) NOT NULL, + `dateCreated` int(10) unsigned NOT NULL, + `seq` int(10) unsigned NOT NULL, + `dataID` int(10) unsigned DEFAULT NULL, + PRIMARY KEY (`src`,`type`,`dst`), + UNIQUE KEY `key_dst` (`dst`,`type`,`src`), + KEY `src` (`src`,`type`,`dateCreated`,`seq`) +) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE={$COLLATE_TEXT}; + +CREATE TABLE `edgedata` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `data` longtext COLLATE {$COLLATE_TEXT} NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE={$COLLATE_TEXT}; + CREATE TABLE `owners_customfieldnumericindex` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `objectPHID` varbinary(64) NOT NULL, @@ -1803,6 +1878,15 @@ CREATE TABLE `owners_customfieldstringindex` ( KEY `key_find` (`indexKey`,`indexValue`(64)) ) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE={$COLLATE_TEXT}; +CREATE TABLE `owners_name_ngrams` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `objectID` int(10) unsigned NOT NULL, + `ngram` char(3) COLLATE {$COLLATE_TEXT} NOT NULL, + PRIMARY KEY (`id`), + KEY `key_object` (`objectID`), + KEY `key_ngram` (`ngram`,`objectID`) +) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE={$COLLATE_TEXT}; + CREATE TABLE `owners_owner` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `packageID` int(10) unsigned NOT NULL, @@ -1815,7 +1899,7 @@ CREATE TABLE `owners_owner` ( CREATE TABLE `owners_package` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `phid` varbinary(64) NOT NULL, - `name` varchar(128) COLLATE {$COLLATE_TEXT} NOT NULL, + `name` varchar(128) CHARACTER SET {$CHARSET_SORT} COLLATE {$COLLATE_SORT} NOT NULL, `originalName` varchar(255) COLLATE {$COLLATE_TEXT} NOT NULL, `description` longtext COLLATE {$COLLATE_TEXT} NOT NULL, `primaryOwnerPHID` varbinary(64) DEFAULT NULL, @@ -1823,8 +1907,7 @@ CREATE TABLE `owners_package` ( `mailKey` binary(20) NOT NULL, `status` varchar(32) COLLATE {$COLLATE_TEXT} NOT NULL, PRIMARY KEY (`id`), - UNIQUE KEY `phid` (`phid`), - UNIQUE KEY `name` (`name`) + UNIQUE KEY `key_phid` (`phid`) ) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE={$COLLATE_TEXT}; CREATE TABLE `owners_packagetransaction` ( @@ -1979,7 +2062,9 @@ CREATE TABLE `phame_blog` ( `dateModified` int(10) unsigned NOT NULL, `viewPolicy` varbinary(64) DEFAULT NULL, `editPolicy` varbinary(64) DEFAULT NULL, - `joinPolicy` varbinary(64) DEFAULT NULL, + `mailKey` binary(20) NOT NULL, + `status` varchar(32) COLLATE {$COLLATE_TEXT} NOT NULL, + `profileImagePHID` varbinary(64) DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `phid` (`phid`), UNIQUE KEY `domain` (`domain`) @@ -2011,7 +2096,7 @@ CREATE TABLE `phame_post` ( `phid` varbinary(64) NOT NULL, `bloggerPHID` varbinary(64) NOT NULL, `title` varchar(255) COLLATE {$COLLATE_TEXT} NOT NULL, - `phameTitle` varchar(64) CHARACTER SET {$CHARSET_SORT} COLLATE {$COLLATE_SORT} NOT NULL, + `phameTitle` varchar(64) CHARACTER SET {$CHARSET_SORT} COLLATE {$COLLATE_SORT} DEFAULT NULL, `body` longtext COLLATE {$COLLATE_TEXT}, `visibility` int(10) unsigned NOT NULL DEFAULT '0', `configData` longtext COLLATE {$COLLATE_TEXT}, @@ -2019,9 +2104,9 @@ CREATE TABLE `phame_post` ( `dateCreated` int(10) unsigned NOT NULL, `dateModified` int(10) unsigned NOT NULL, `blogPHID` varbinary(64) DEFAULT NULL, + `mailKey` binary(20) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `phid` (`phid`), - UNIQUE KEY `phameTitle` (`bloggerPHID`,`phameTitle`), KEY `bloggerPosts` (`bloggerPHID`,`visibility`,`datePublished`,`id`) ) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE={$COLLATE_TEXT}; @@ -2046,6 +2131,24 @@ CREATE TABLE `phame_posttransaction` ( KEY `key_object` (`objectPHID`) ) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE={$COLLATE_TEXT}; +CREATE TABLE `phame_posttransaction_comment` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `phid` varbinary(64) NOT NULL, + `transactionPHID` varbinary(64) DEFAULT NULL, + `authorPHID` varbinary(64) NOT NULL, + `viewPolicy` varbinary(64) NOT NULL, + `editPolicy` varbinary(64) NOT NULL, + `commentVersion` int(10) unsigned NOT NULL, + `content` longtext COLLATE {$COLLATE_TEXT} NOT NULL, + `contentSource` longtext COLLATE {$COLLATE_TEXT} NOT NULL, + `isDeleted` tinyint(1) NOT NULL, + `dateCreated` int(10) unsigned NOT NULL, + `dateModified` int(10) unsigned NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `key_phid` (`phid`), + UNIQUE KEY `key_version` (`transactionPHID`,`commentVersion`) +) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE={$COLLATE_TEXT}; + CREATE DATABASE /*!32312 IF NOT EXISTS*/ `{$NAMESPACE}_phriction` /*!40100 DEFAULT CHARACTER SET {$CHARSET} COLLATE {$COLLATE_TEXT} */; USE `{$NAMESPACE}_phriction`; @@ -2172,22 +2275,31 @@ CREATE TABLE `project` ( `dateCreated` int(10) unsigned NOT NULL, `dateModified` int(10) unsigned NOT NULL, `status` varchar(32) COLLATE {$COLLATE_TEXT} NOT NULL, - `subprojectPHIDs` longtext COLLATE {$COLLATE_TEXT} NOT NULL, - `phrictionSlug` varchar(128) COLLATE {$COLLATE_TEXT} DEFAULT NULL, - `viewPolicy` varbinary(64) DEFAULT NULL, - `editPolicy` varbinary(64) DEFAULT NULL, - `joinPolicy` varbinary(64) DEFAULT NULL, + `viewPolicy` varbinary(64) NOT NULL, + `editPolicy` varbinary(64) NOT NULL, + `joinPolicy` varbinary(64) NOT NULL, `isMembershipLocked` tinyint(1) NOT NULL DEFAULT '0', `profileImagePHID` varbinary(64) DEFAULT NULL, `icon` varchar(32) COLLATE {$COLLATE_TEXT} NOT NULL, `color` varchar(32) COLLATE {$COLLATE_TEXT} NOT NULL, `mailKey` binary(20) NOT NULL, + `primarySlug` varchar(128) COLLATE {$COLLATE_TEXT} DEFAULT NULL, + `parentProjectPHID` varbinary(64) DEFAULT NULL, + `hasWorkboard` tinyint(1) NOT NULL, + `hasMilestones` tinyint(1) NOT NULL, + `hasSubprojects` tinyint(1) NOT NULL, + `milestoneNumber` int(10) unsigned DEFAULT NULL, + `projectPath` varbinary(64) NOT NULL, + `projectDepth` int(10) unsigned NOT NULL, + `projectPathKey` binary(4) NOT NULL, PRIMARY KEY (`id`), - UNIQUE KEY `phid` (`phid`), - UNIQUE KEY `name` (`name`), - UNIQUE KEY `phrictionSlug` (`phrictionSlug`), + UNIQUE KEY `key_pathkey` (`projectPathKey`), + UNIQUE KEY `key_phid` (`phid`), + UNIQUE KEY `key_primaryslug` (`primarySlug`), + UNIQUE KEY `key_milestone` (`parentProjectPHID`,`milestoneNumber`), KEY `key_icon` (`icon`), - KEY `key_color` (`color`) + KEY `key_color` (`color`), + KEY `key_path` (`projectPath`,`projectDepth`) ) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE={$COLLATE_TEXT}; CREATE TABLE `project_column` ( @@ -2347,9 +2459,11 @@ CREATE TABLE `repository` ( `credentialPHID` varbinary(64) DEFAULT NULL, `almanacServicePHID` varbinary(64) DEFAULT NULL, `spacePHID` varbinary(64) DEFAULT NULL, + `repositorySlug` varchar(64) CHARACTER SET {$CHARSET_SORT} COLLATE {$COLLATE_SORT} DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `callsign` (`callsign`), - UNIQUE KEY `phid` (`phid`), + UNIQUE KEY `key_phid` (`phid`), + UNIQUE KEY `key_slug` (`repositorySlug`), KEY `key_vcs` (`versionControlSystem`), KEY `key_name` (`name`(128)), KEY `key_space` (`spacePHID`) @@ -2422,7 +2536,7 @@ CREATE TABLE `repository_coverage` ( `pathID` int(10) unsigned NOT NULL, `coverage` longblob NOT NULL, PRIMARY KEY (`id`), - KEY `key_path` (`branchID`,`pathID`,`commitID`) + UNIQUE KEY `key_path` (`branchID`,`pathID`,`commitID`) ) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE={$COLLATE_TEXT}; CREATE TABLE `repository_filesystem` ( @@ -2537,6 +2651,7 @@ CREATE TABLE `repository_pushlog` ( CREATE TABLE `repository_refcursor` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `phid` varbinary(64) NOT NULL, `repositoryPHID` varbinary(64) NOT NULL, `refType` varchar(32) COLLATE {$COLLATE_TEXT} NOT NULL, `refNameHash` binary(12) NOT NULL, @@ -2545,6 +2660,7 @@ CREATE TABLE `repository_refcursor` ( `commitIdentifier` varchar(40) COLLATE {$COLLATE_TEXT} NOT NULL, `isClosed` tinyint(1) NOT NULL, PRIMARY KEY (`id`), + UNIQUE KEY `key_phid` (`phid`), KEY `key_cursor` (`repositoryPHID`,`refType`,`refNameHash`) ) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE={$COLLATE_TEXT}; @@ -2600,6 +2716,15 @@ CREATE TABLE `repository_transaction` ( KEY `key_object` (`objectPHID`) ) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE={$COLLATE_TEXT}; +CREATE TABLE `repository_uriindex` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `repositoryPHID` varbinary(64) NOT NULL, + `repositoryURI` longtext COLLATE {$COLLATE_TEXT} NOT NULL, + PRIMARY KEY (`id`), + KEY `key_repository` (`repositoryPHID`), + KEY `key_uri` (`repositoryURI`(128)) +) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE={$COLLATE_TEXT}; + CREATE TABLE `repository_vcspassword` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `userPHID` varbinary(64) NOT NULL, @@ -2645,6 +2770,58 @@ CREATE TABLE `search_documentrelationship` ( KEY `relation` (`relation`,`relatedPHID`) ) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE={$COLLATE_TEXT}; +CREATE TABLE `search_editengineconfiguration` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `phid` varbinary(64) NOT NULL, + `engineKey` varchar(64) COLLATE {$COLLATE_TEXT} NOT NULL, + `builtinKey` varchar(64) COLLATE {$COLLATE_TEXT} DEFAULT NULL, + `name` varchar(255) COLLATE {$COLLATE_TEXT} NOT NULL, + `viewPolicy` varbinary(64) NOT NULL, + `properties` longtext COLLATE {$COLLATE_TEXT} NOT NULL, + `isDisabled` tinyint(1) NOT NULL DEFAULT '0', + `isDefault` tinyint(1) NOT NULL DEFAULT '0', + `dateCreated` int(10) unsigned NOT NULL, + `dateModified` int(10) unsigned NOT NULL, + `isEdit` tinyint(1) NOT NULL, + `createOrder` int(10) unsigned NOT NULL, + `editOrder` int(10) unsigned NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `key_phid` (`phid`), + UNIQUE KEY `key_engine` (`engineKey`,`builtinKey`), + KEY `key_default` (`engineKey`,`isDefault`,`isDisabled`), + KEY `key_edit` (`engineKey`,`isEdit`,`isDisabled`) +) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE={$COLLATE_TEXT}; + +CREATE TABLE `search_editengineconfigurationtransaction` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `phid` varbinary(64) NOT NULL, + `authorPHID` varbinary(64) NOT NULL, + `objectPHID` varbinary(64) NOT NULL, + `viewPolicy` varbinary(64) NOT NULL, + `editPolicy` varbinary(64) NOT NULL, + `commentPHID` varbinary(64) DEFAULT NULL, + `commentVersion` int(10) unsigned NOT NULL, + `transactionType` varchar(32) COLLATE {$COLLATE_TEXT} NOT NULL, + `oldValue` longtext COLLATE {$COLLATE_TEXT} NOT NULL, + `newValue` longtext COLLATE {$COLLATE_TEXT} NOT NULL, + `contentSource` longtext COLLATE {$COLLATE_TEXT} NOT NULL, + `metadata` longtext COLLATE {$COLLATE_TEXT} NOT NULL, + `dateCreated` int(10) unsigned NOT NULL, + `dateModified` int(10) unsigned NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `key_phid` (`phid`), + KEY `key_object` (`objectPHID`) +) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE={$COLLATE_TEXT}; + +CREATE TABLE `search_indexversion` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `objectPHID` varbinary(64) NOT NULL, + `extensionKey` varchar(64) COLLATE {$COLLATE_TEXT} NOT NULL, + `version` varchar(128) COLLATE {$COLLATE_TEXT} NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `key_object` (`objectPHID`,`extensionKey`) +) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE={$COLLATE_TEXT}; + CREATE TABLE `search_namedquery` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `userPHID` varbinary(64) NOT NULL, @@ -2660,6 +2837,43 @@ CREATE TABLE `search_namedquery` ( UNIQUE KEY `key_userquery` (`userPHID`,`engineClassName`,`queryKey`) ) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE={$COLLATE_TEXT}; +CREATE TABLE `search_profilepanelconfiguration` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `phid` varbinary(64) NOT NULL, + `profilePHID` varbinary(64) NOT NULL, + `panelKey` varchar(64) COLLATE {$COLLATE_TEXT} NOT NULL, + `builtinKey` varchar(64) COLLATE {$COLLATE_TEXT} DEFAULT NULL, + `panelOrder` int(10) unsigned DEFAULT NULL, + `visibility` varchar(32) COLLATE {$COLLATE_TEXT} NOT NULL, + `panelProperties` longtext COLLATE {$COLLATE_TEXT} NOT NULL, + `dateCreated` int(10) unsigned NOT NULL, + `dateModified` int(10) unsigned NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `key_phid` (`phid`), + KEY `key_profile` (`profilePHID`,`panelOrder`) +) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE={$COLLATE_TEXT}; + +CREATE TABLE `search_profilepanelconfigurationtransaction` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `phid` varbinary(64) NOT NULL, + `authorPHID` varbinary(64) NOT NULL, + `objectPHID` varbinary(64) NOT NULL, + `viewPolicy` varbinary(64) NOT NULL, + `editPolicy` varbinary(64) NOT NULL, + `commentPHID` varbinary(64) DEFAULT NULL, + `commentVersion` int(10) unsigned NOT NULL, + `transactionType` varchar(32) COLLATE {$COLLATE_TEXT} NOT NULL, + `oldValue` longtext COLLATE {$COLLATE_TEXT} NOT NULL, + `newValue` longtext COLLATE {$COLLATE_TEXT} NOT NULL, + `contentSource` longtext COLLATE {$COLLATE_TEXT} NOT NULL, + `metadata` longtext COLLATE {$COLLATE_TEXT} NOT NULL, + `dateCreated` int(10) unsigned NOT NULL, + `dateModified` int(10) unsigned NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `key_phid` (`phid`), + KEY `key_object` (`objectPHID`) +) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE={$COLLATE_TEXT}; + CREATE TABLE `search_savedquery` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `engineClassName` varchar(255) COLLATE {$COLLATE_TEXT} NOT NULL, @@ -3144,15 +3358,17 @@ CREATE TABLE `worker_triggerevent` ( KEY `key_next` (`nextEventEpoch`) ) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE={$COLLATE_TEXT}; -CREATE DATABASE /*!32312 IF NOT EXISTS*/ `{$NAMESPACE}_xhpastview` /*!40100 DEFAULT CHARACTER SET {$CHARSET} COLLATE {$COLLATE_TEXT} */; +CREATE DATABASE /*!32312 IF NOT EXISTS*/ `{$NAMESPACE}_xhpast` /*!40100 DEFAULT CHARACTER SET {$CHARSET} COLLATE {$COLLATE_TEXT} */; -USE `{$NAMESPACE}_xhpastview`; +USE `{$NAMESPACE}_xhpast`; -CREATE TABLE `xhpastview_parsetree` ( +CREATE TABLE `xhpast_parsetree` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `authorPHID` varbinary(64) DEFAULT NULL, `input` longtext COLLATE {$COLLATE_TEXT} NOT NULL, + `returnCode` int(10) NOT NULL, `stdout` longtext COLLATE {$COLLATE_TEXT} NOT NULL, + `stderr` longtext COLLATE {$COLLATE_TEXT} NOT NULL, `dateCreated` int(10) unsigned NOT NULL, `dateModified` int(10) unsigned NOT NULL, PRIMARY KEY (`id`) @@ -4286,6 +4502,7 @@ CREATE TABLE `auth_providerconfigtransaction` ( CREATE TABLE `auth_sshkey` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `phid` varbinary(64) NOT NULL, `objectPHID` varbinary(64) NOT NULL, `name` varchar(255) COLLATE {$COLLATE_TEXT} NOT NULL, `keyType` varchar(255) COLLATE {$COLLATE_TEXT} NOT NULL, @@ -4297,6 +4514,7 @@ CREATE TABLE `auth_sshkey` ( `isTrusted` tinyint(1) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `key_unique` (`keyIndex`), + UNIQUE KEY `key_phid` (`phid`), KEY `key_object` (`objectPHID`) ) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE={$COLLATE_TEXT}; @@ -5471,6 +5689,7 @@ CREATE TABLE `phurl_url` ( `dateModified` int(10) unsigned NOT NULL, `alias` varchar(64) CHARACTER SET {$CHARSET_SORT} COLLATE {$COLLATE_SORT} DEFAULT NULL, `authorPHID` varbinary(64) NOT NULL, + `mailKey` binary(20) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `key_phid` (`phid`), UNIQUE KEY `key_instance` (`alias`), diff --git a/scripts/celerity/generate_sprites.php b/scripts/celerity/generate_sprites.php index 97e3f70a19..61f63d155d 100755 --- a/scripts/celerity/generate_sprites.php +++ b/scripts/celerity/generate_sprites.php @@ -29,9 +29,7 @@ $generator = new CeleritySpriteGenerator(); $sheets = array( 'menu' => $generator->buildMenuSheet(), 'tokens' => $generator->buildTokenSheet(), - 'main-header' => $generator->buildMainHeaderSheet(), 'login' => $generator->buildLoginSheet(), - 'projects' => $generator->buildProjectsSheet(), ); list($err) = exec_manual('optipng'); diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 3f8d654711..720a5d0c3c 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1147,6 +1147,7 @@ phutil_register_library_map(array( 'HeraldEffect' => 'applications/herald/engine/HeraldEffect.php', 'HeraldEmptyFieldValue' => 'applications/herald/value/HeraldEmptyFieldValue.php', 'HeraldEngine' => 'applications/herald/engine/HeraldEngine.php', + 'HeraldExactProjectsField' => 'applications/project/herald/HeraldExactProjectsField.php', 'HeraldField' => 'applications/herald/field/HeraldField.php', 'HeraldFieldGroup' => 'applications/herald/field/HeraldFieldGroup.php', 'HeraldFieldTestCase' => 'applications/herald/field/__tests__/HeraldFieldTestCase.php', @@ -1491,6 +1492,7 @@ phutil_register_library_map(array( 'PHUIHandleTagListView' => 'applications/phid/view/PHUIHandleTagListView.php', 'PHUIHandleView' => 'applications/phid/view/PHUIHandleView.php', 'PHUIHeaderView' => 'view/phui/PHUIHeaderView.php', + 'PHUIIconCircleView' => 'view/phui/PHUIIconCircleView.php', 'PHUIIconExample' => 'applications/uiexample/examples/PHUIIconExample.php', 'PHUIIconView' => 'view/phui/PHUIIconView.php', 'PHUIImageMaskExample' => 'applications/uiexample/examples/PHUIImageMaskExample.php', @@ -2154,6 +2156,7 @@ phutil_register_library_map(array( 'PhabricatorDisabledUserController' => 'applications/auth/controller/PhabricatorDisabledUserController.php', 'PhabricatorDisplayPreferencesSettingsPanel' => 'applications/settings/panel/PhabricatorDisplayPreferencesSettingsPanel.php', 'PhabricatorDisqusAuthProvider' => 'applications/auth/provider/PhabricatorDisqusAuthProvider.php', + 'PhabricatorDividerProfilePanel' => 'applications/search/profilepanel/PhabricatorDividerProfilePanel.php', 'PhabricatorDivinerApplication' => 'applications/diviner/application/PhabricatorDivinerApplication.php', 'PhabricatorDoorkeeperApplication' => 'applications/doorkeeper/application/PhabricatorDoorkeeperApplication.php', 'PhabricatorDraft' => 'applications/draft/storage/PhabricatorDraft.php', @@ -2220,6 +2223,7 @@ phutil_register_library_map(array( 'PhabricatorEventListener' => 'infrastructure/events/PhabricatorEventListener.php', 'PhabricatorEventType' => 'infrastructure/events/constant/PhabricatorEventType.php', 'PhabricatorExampleEventListener' => 'infrastructure/events/PhabricatorExampleEventListener.php', + 'PhabricatorExecFutureFileUploadSource' => 'applications/files/uploadsource/PhabricatorExecFutureFileUploadSource.php', 'PhabricatorExtendedPolicyInterface' => 'applications/policy/interface/PhabricatorExtendedPolicyInterface.php', 'PhabricatorExtendingPhabricatorConfigOptions' => 'applications/config/option/PhabricatorExtendingPhabricatorConfigOptions.php', 'PhabricatorExtensionsSetupCheck' => 'applications/config/check/PhabricatorExtensionsSetupCheck.php', @@ -2309,9 +2313,12 @@ phutil_register_library_map(array( 'PhabricatorFileUploadController' => 'applications/files/controller/PhabricatorFileUploadController.php', 'PhabricatorFileUploadDialogController' => 'applications/files/controller/PhabricatorFileUploadDialogController.php', 'PhabricatorFileUploadException' => 'applications/files/exception/PhabricatorFileUploadException.php', + 'PhabricatorFileUploadSource' => 'applications/files/uploadsource/PhabricatorFileUploadSource.php', 'PhabricatorFileinfoSetupCheck' => 'applications/config/check/PhabricatorFileinfoSetupCheck.php', 'PhabricatorFilesApplication' => 'applications/files/application/PhabricatorFilesApplication.php', 'PhabricatorFilesApplicationStorageEnginePanel' => 'applications/files/applicationpanel/PhabricatorFilesApplicationStorageEnginePanel.php', + 'PhabricatorFilesBuiltinFile' => 'applications/files/builtin/PhabricatorFilesBuiltinFile.php', + 'PhabricatorFilesComposeIconBuiltinFile' => 'applications/files/builtin/PhabricatorFilesComposeIconBuiltinFile.php', 'PhabricatorFilesConfigOptions' => 'applications/files/config/PhabricatorFilesConfigOptions.php', 'PhabricatorFilesManagementCatWorkflow' => 'applications/files/management/PhabricatorFilesManagementCatWorkflow.php', 'PhabricatorFilesManagementCompactWorkflow' => 'applications/files/management/PhabricatorFilesManagementCompactWorkflow.php', @@ -2320,6 +2327,7 @@ phutil_register_library_map(array( 'PhabricatorFilesManagementPurgeWorkflow' => 'applications/files/management/PhabricatorFilesManagementPurgeWorkflow.php', 'PhabricatorFilesManagementRebuildWorkflow' => 'applications/files/management/PhabricatorFilesManagementRebuildWorkflow.php', 'PhabricatorFilesManagementWorkflow' => 'applications/files/management/PhabricatorFilesManagementWorkflow.php', + 'PhabricatorFilesOnDiskBuiltinFile' => 'applications/files/builtin/PhabricatorFilesOnDiskBuiltinFile.php', 'PhabricatorFilesOutboundRequestAction' => 'applications/files/action/PhabricatorFilesOutboundRequestAction.php', 'PhabricatorFlag' => 'applications/flag/storage/PhabricatorFlag.php', 'PhabricatorFlagAddFlagHeraldAction' => 'applications/flag/herald/PhabricatorFlagAddFlagHeraldAction.php', @@ -2551,6 +2559,7 @@ phutil_register_library_map(array( 'PhabricatorMetaMTASendGridReceiveController' => 'applications/metamta/controller/PhabricatorMetaMTASendGridReceiveController.php', 'PhabricatorMetaMTAWorker' => 'applications/metamta/PhabricatorMetaMTAWorker.php', 'PhabricatorMetronomicTriggerClock' => 'infrastructure/daemon/workers/clock/PhabricatorMetronomicTriggerClock.php', + 'PhabricatorMotivatorProfilePanel' => 'applications/search/profilepanel/PhabricatorMotivatorProfilePanel.php', 'PhabricatorMultiColumnUIExample' => 'applications/uiexample/examples/PhabricatorMultiColumnUIExample.php', 'PhabricatorMultiFactorSettingsPanel' => 'applications/settings/panel/PhabricatorMultiFactorSettingsPanel.php', 'PhabricatorMultimeterApplication' => 'applications/multimeter/application/PhabricatorMultimeterApplication.php', @@ -2723,6 +2732,7 @@ phutil_register_library_map(array( 'PhabricatorPeopleCreateController' => 'applications/people/controller/PhabricatorPeopleCreateController.php', 'PhabricatorPeopleDatasource' => 'applications/people/typeahead/PhabricatorPeopleDatasource.php', 'PhabricatorPeopleDeleteController' => 'applications/people/controller/PhabricatorPeopleDeleteController.php', + 'PhabricatorPeopleDetailsProfilePanel' => 'applications/people/profilepanel/PhabricatorPeopleDetailsProfilePanel.php', 'PhabricatorPeopleDisableController' => 'applications/people/controller/PhabricatorPeopleDisableController.php', 'PhabricatorPeopleEmpowerController' => 'applications/people/controller/PhabricatorPeopleEmpowerController.php', 'PhabricatorPeopleExternalPHIDType' => 'applications/people/phid/PhabricatorPeopleExternalPHIDType.php', @@ -2741,7 +2751,9 @@ phutil_register_library_map(array( 'PhabricatorPeopleOwnerDatasource' => 'applications/people/typeahead/PhabricatorPeopleOwnerDatasource.php', 'PhabricatorPeopleProfileController' => 'applications/people/controller/PhabricatorPeopleProfileController.php', 'PhabricatorPeopleProfileEditController' => 'applications/people/controller/PhabricatorPeopleProfileEditController.php', + 'PhabricatorPeopleProfilePanelEngine' => 'applications/people/engine/PhabricatorPeopleProfilePanelEngine.php', 'PhabricatorPeopleProfilePictureController' => 'applications/people/controller/PhabricatorPeopleProfilePictureController.php', + 'PhabricatorPeopleProfileViewController' => 'applications/people/controller/PhabricatorPeopleProfileViewController.php', 'PhabricatorPeopleQuery' => 'applications/people/query/PhabricatorPeopleQuery.php', 'PhabricatorPeopleRenameController' => 'applications/people/controller/PhabricatorPeopleRenameController.php', 'PhabricatorPeopleSearchEngine' => 'applications/people/query/PhabricatorPeopleSearchEngine.php', @@ -2832,11 +2844,11 @@ phutil_register_library_map(array( 'PhabricatorProfilePanelConfiguration' => 'applications/search/storage/PhabricatorProfilePanelConfiguration.php', 'PhabricatorProfilePanelConfigurationQuery' => 'applications/search/query/PhabricatorProfilePanelConfigurationQuery.php', 'PhabricatorProfilePanelConfigurationTransaction' => 'applications/search/storage/PhabricatorProfilePanelConfigurationTransaction.php', + 'PhabricatorProfilePanelConfigurationTransactionQuery' => 'applications/search/query/PhabricatorProfilePanelConfigurationTransactionQuery.php', 'PhabricatorProfilePanelEditEngine' => 'applications/search/editor/PhabricatorProfilePanelEditEngine.php', 'PhabricatorProfilePanelEditor' => 'applications/search/editor/PhabricatorProfilePanelEditor.php', 'PhabricatorProfilePanelEngine' => 'applications/search/engine/PhabricatorProfilePanelEngine.php', 'PhabricatorProfilePanelIconSet' => 'applications/search/profilepanel/PhabricatorProfilePanelIconSet.php', - 'PhabricatorProfilePanelInterface' => 'applications/search/interface/PhabricatorProfilePanelInterface.php', 'PhabricatorProfilePanelPHIDType' => 'applications/search/phidtype/PhabricatorProfilePanelPHIDType.php', 'PhabricatorProject' => 'applications/project/storage/PhabricatorProject.php', 'PhabricatorProjectAddHeraldAction' => 'applications/project/herald/PhabricatorProjectAddHeraldAction.php', @@ -2846,6 +2858,7 @@ phutil_register_library_map(array( 'PhabricatorProjectBoardImportController' => 'applications/project/controller/PhabricatorProjectBoardImportController.php', 'PhabricatorProjectBoardReorderController' => 'applications/project/controller/PhabricatorProjectBoardReorderController.php', 'PhabricatorProjectBoardViewController' => 'applications/project/controller/PhabricatorProjectBoardViewController.php', + 'PhabricatorProjectColorsConfigOptionType' => 'applications/project/config/PhabricatorProjectColorsConfigOptionType.php', 'PhabricatorProjectColumn' => 'applications/project/storage/PhabricatorProjectColumn.php', 'PhabricatorProjectColumnDetailController' => 'applications/project/controller/PhabricatorProjectColumnDetailController.php', 'PhabricatorProjectColumnEditController' => 'applications/project/controller/PhabricatorProjectColumnEditController.php', @@ -2872,10 +2885,13 @@ phutil_register_library_map(array( 'PhabricatorProjectEditController' => 'applications/project/controller/PhabricatorProjectEditController.php', 'PhabricatorProjectEditEngine' => 'applications/project/engine/PhabricatorProjectEditEngine.php', 'PhabricatorProjectEditPictureController' => 'applications/project/controller/PhabricatorProjectEditPictureController.php', - 'PhabricatorProjectFeedController' => 'applications/project/controller/PhabricatorProjectFeedController.php', 'PhabricatorProjectFulltextEngine' => 'applications/project/search/PhabricatorProjectFulltextEngine.php', 'PhabricatorProjectHeraldAction' => 'applications/project/herald/PhabricatorProjectHeraldAction.php', + 'PhabricatorProjectHeraldAdapter' => 'applications/project/herald/PhabricatorProjectHeraldAdapter.php', + 'PhabricatorProjectHeraldFieldGroup' => 'applications/project/herald/PhabricatorProjectHeraldFieldGroup.php', + 'PhabricatorProjectHistoryController' => 'applications/project/controller/PhabricatorProjectHistoryController.php', 'PhabricatorProjectIconSet' => 'applications/project/icon/PhabricatorProjectIconSet.php', + 'PhabricatorProjectIconsConfigOptionType' => 'applications/project/config/PhabricatorProjectIconsConfigOptionType.php', 'PhabricatorProjectInterface' => 'applications/project/interface/PhabricatorProjectInterface.php', 'PhabricatorProjectListController' => 'applications/project/controller/PhabricatorProjectListController.php', 'PhabricatorProjectListView' => 'applications/project/view/PhabricatorProjectListView.php', @@ -2886,12 +2902,14 @@ phutil_register_library_map(array( 'PhabricatorProjectLogicalUserDatasource' => 'applications/project/typeahead/PhabricatorProjectLogicalUserDatasource.php', 'PhabricatorProjectLogicalViewerDatasource' => 'applications/project/typeahead/PhabricatorProjectLogicalViewerDatasource.php', 'PhabricatorProjectMaterializedMemberEdgeType' => 'applications/project/edge/PhabricatorProjectMaterializedMemberEdgeType.php', + 'PhabricatorProjectMemberListView' => 'applications/project/view/PhabricatorProjectMemberListView.php', 'PhabricatorProjectMemberOfProjectEdgeType' => 'applications/project/edge/PhabricatorProjectMemberOfProjectEdgeType.php', + 'PhabricatorProjectMembersAddController' => 'applications/project/controller/PhabricatorProjectMembersAddController.php', 'PhabricatorProjectMembersDatasource' => 'applications/project/typeahead/PhabricatorProjectMembersDatasource.php', - 'PhabricatorProjectMembersEditController' => 'applications/project/controller/PhabricatorProjectMembersEditController.php', 'PhabricatorProjectMembersPolicyRule' => 'applications/project/policyrule/PhabricatorProjectMembersPolicyRule.php', 'PhabricatorProjectMembersProfilePanel' => 'applications/project/profilepanel/PhabricatorProjectMembersProfilePanel.php', 'PhabricatorProjectMembersRemoveController' => 'applications/project/controller/PhabricatorProjectMembersRemoveController.php', + 'PhabricatorProjectMembersViewController' => 'applications/project/controller/PhabricatorProjectMembersViewController.php', 'PhabricatorProjectMilestonesController' => 'applications/project/controller/PhabricatorProjectMilestonesController.php', 'PhabricatorProjectMoveController' => 'applications/project/controller/PhabricatorProjectMoveController.php', 'PhabricatorProjectNameContextFreeGrammar' => 'applications/project/lipsum/PhabricatorProjectNameContextFreeGrammar.php', @@ -2902,6 +2920,7 @@ phutil_register_library_map(array( 'PhabricatorProjectPHIDResolver' => 'applications/phid/resolver/PhabricatorProjectPHIDResolver.php', 'PhabricatorProjectPanelController' => 'applications/project/controller/PhabricatorProjectPanelController.php', 'PhabricatorProjectProfileController' => 'applications/project/controller/PhabricatorProjectProfileController.php', + 'PhabricatorProjectProfilePanelEngine' => 'applications/project/engine/PhabricatorProjectProfilePanelEngine.php', 'PhabricatorProjectProjectHasMemberEdgeType' => 'applications/project/edge/PhabricatorProjectProjectHasMemberEdgeType.php', 'PhabricatorProjectProjectHasObjectEdgeType' => 'applications/project/edge/PhabricatorProjectProjectHasObjectEdgeType.php', 'PhabricatorProjectProjectPHIDType' => 'applications/project/phid/PhabricatorProjectProjectPHIDType.php', @@ -2910,6 +2929,8 @@ phutil_register_library_map(array( 'PhabricatorProjectSchemaSpec' => 'applications/project/storage/PhabricatorProjectSchemaSpec.php', 'PhabricatorProjectSearchEngine' => 'applications/project/query/PhabricatorProjectSearchEngine.php', 'PhabricatorProjectSearchField' => 'applications/project/searchfield/PhabricatorProjectSearchField.php', + 'PhabricatorProjectSilenceController' => 'applications/project/controller/PhabricatorProjectSilenceController.php', + 'PhabricatorProjectSilencedEdgeType' => 'applications/project/edge/PhabricatorProjectSilencedEdgeType.php', 'PhabricatorProjectSlug' => 'applications/project/storage/PhabricatorProjectSlug.php', 'PhabricatorProjectStandardCustomField' => 'applications/project/customfield/PhabricatorProjectStandardCustomField.php', 'PhabricatorProjectStatus' => 'applications/project/constants/PhabricatorProjectStatus.php', @@ -2918,12 +2939,13 @@ phutil_register_library_map(array( 'PhabricatorProjectTransaction' => 'applications/project/storage/PhabricatorProjectTransaction.php', 'PhabricatorProjectTransactionEditor' => 'applications/project/editor/PhabricatorProjectTransactionEditor.php', 'PhabricatorProjectTransactionQuery' => 'applications/project/query/PhabricatorProjectTransactionQuery.php', - 'PhabricatorProjectTypeConfigOptionType' => 'applications/project/config/PhabricatorProjectTypeConfigOptionType.php', 'PhabricatorProjectUIEventListener' => 'applications/project/events/PhabricatorProjectUIEventListener.php', 'PhabricatorProjectUpdateController' => 'applications/project/controller/PhabricatorProjectUpdateController.php', 'PhabricatorProjectUserFunctionDatasource' => 'applications/project/typeahead/PhabricatorProjectUserFunctionDatasource.php', + 'PhabricatorProjectUserListView' => 'applications/project/view/PhabricatorProjectUserListView.php', 'PhabricatorProjectViewController' => 'applications/project/controller/PhabricatorProjectViewController.php', 'PhabricatorProjectWatchController' => 'applications/project/controller/PhabricatorProjectWatchController.php', + 'PhabricatorProjectWatcherListView' => 'applications/project/view/PhabricatorProjectWatcherListView.php', 'PhabricatorProjectWorkboardProfilePanel' => 'applications/project/profilepanel/PhabricatorProjectWorkboardProfilePanel.php', 'PhabricatorProjectsEditEngineExtension' => 'applications/project/engineextension/PhabricatorProjectsEditEngineExtension.php', 'PhabricatorProjectsEditField' => 'applications/transactions/editfield/PhabricatorProjectsEditField.php', @@ -5233,6 +5255,7 @@ phutil_register_library_map(array( 'HeraldEffect' => 'Phobject', 'HeraldEmptyFieldValue' => 'HeraldFieldValue', 'HeraldEngine' => 'Phobject', + 'HeraldExactProjectsField' => 'HeraldField', 'HeraldField' => 'Phobject', 'HeraldFieldGroup' => 'HeraldGroup', 'HeraldFieldTestCase' => 'PhutilTestCase', @@ -5635,6 +5658,7 @@ phutil_register_library_map(array( 'PHUIHandleTagListView' => 'AphrontTagView', 'PHUIHandleView' => 'AphrontView', 'PHUIHeaderView' => 'AphrontTagView', + 'PHUIIconCircleView' => 'AphrontTagView', 'PHUIIconExample' => 'PhabricatorUIExample', 'PHUIIconView' => 'AphrontTagView', 'PHUIImageMaskExample' => 'PhabricatorUIExample', @@ -6409,6 +6433,7 @@ phutil_register_library_map(array( 'PhabricatorDisabledUserController' => 'PhabricatorAuthController', 'PhabricatorDisplayPreferencesSettingsPanel' => 'PhabricatorSettingsPanel', 'PhabricatorDisqusAuthProvider' => 'PhabricatorOAuth2AuthProvider', + 'PhabricatorDividerProfilePanel' => 'PhabricatorProfilePanel', 'PhabricatorDivinerApplication' => 'PhabricatorApplication', 'PhabricatorDoorkeeperApplication' => 'PhabricatorApplication', 'PhabricatorDraft' => 'PhabricatorDraftDAO', @@ -6482,6 +6507,7 @@ phutil_register_library_map(array( 'PhabricatorEventListener' => 'PhutilEventListener', 'PhabricatorEventType' => 'PhutilEventType', 'PhabricatorExampleEventListener' => 'PhabricatorEventListener', + 'PhabricatorExecFutureFileUploadSource' => 'PhabricatorFileUploadSource', 'PhabricatorExtendingPhabricatorConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorExtensionsSetupCheck' => 'PhabricatorSetupCheck', 'PhabricatorExternalAccount' => array( @@ -6599,9 +6625,12 @@ phutil_register_library_map(array( 'PhabricatorFileUploadController' => 'PhabricatorFileController', 'PhabricatorFileUploadDialogController' => 'PhabricatorFileController', 'PhabricatorFileUploadException' => 'Exception', + 'PhabricatorFileUploadSource' => 'Phobject', 'PhabricatorFileinfoSetupCheck' => 'PhabricatorSetupCheck', 'PhabricatorFilesApplication' => 'PhabricatorApplication', 'PhabricatorFilesApplicationStorageEnginePanel' => 'PhabricatorApplicationConfigurationPanel', + 'PhabricatorFilesBuiltinFile' => 'Phobject', + 'PhabricatorFilesComposeIconBuiltinFile' => 'PhabricatorFilesBuiltinFile', 'PhabricatorFilesConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorFilesManagementCatWorkflow' => 'PhabricatorFilesManagementWorkflow', 'PhabricatorFilesManagementCompactWorkflow' => 'PhabricatorFilesManagementWorkflow', @@ -6610,6 +6639,7 @@ phutil_register_library_map(array( 'PhabricatorFilesManagementPurgeWorkflow' => 'PhabricatorFilesManagementWorkflow', 'PhabricatorFilesManagementRebuildWorkflow' => 'PhabricatorFilesManagementWorkflow', 'PhabricatorFilesManagementWorkflow' => 'PhabricatorManagementWorkflow', + 'PhabricatorFilesOnDiskBuiltinFile' => 'PhabricatorFilesBuiltinFile', 'PhabricatorFilesOutboundRequestAction' => 'PhabricatorSystemAction', 'PhabricatorFlag' => array( 'PhabricatorFlagDAO', @@ -6858,6 +6888,7 @@ phutil_register_library_map(array( 'PhabricatorMetaMTASendGridReceiveController' => 'PhabricatorMetaMTAController', 'PhabricatorMetaMTAWorker' => 'PhabricatorWorker', 'PhabricatorMetronomicTriggerClock' => 'PhabricatorTriggerClock', + 'PhabricatorMotivatorProfilePanel' => 'PhabricatorProfilePanel', 'PhabricatorMultiColumnUIExample' => 'PhabricatorUIExample', 'PhabricatorMultiFactorSettingsPanel' => 'PhabricatorSettingsPanel', 'PhabricatorMultimeterApplication' => 'PhabricatorApplication', @@ -7060,11 +7091,12 @@ phutil_register_library_map(array( 'PhabricatorPeopleAnyOwnerDatasource' => 'PhabricatorTypeaheadDatasource', 'PhabricatorPeopleApplication' => 'PhabricatorApplication', 'PhabricatorPeopleApproveController' => 'PhabricatorPeopleController', - 'PhabricatorPeopleCalendarController' => 'PhabricatorPeopleController', + 'PhabricatorPeopleCalendarController' => 'PhabricatorPeopleProfileController', 'PhabricatorPeopleController' => 'PhabricatorController', 'PhabricatorPeopleCreateController' => 'PhabricatorPeopleController', 'PhabricatorPeopleDatasource' => 'PhabricatorTypeaheadDatasource', 'PhabricatorPeopleDeleteController' => 'PhabricatorPeopleController', + 'PhabricatorPeopleDetailsProfilePanel' => 'PhabricatorProfilePanel', 'PhabricatorPeopleDisableController' => 'PhabricatorPeopleController', 'PhabricatorPeopleEmpowerController' => 'PhabricatorPeopleController', 'PhabricatorPeopleExternalPHIDType' => 'PhabricatorPHIDType', @@ -7082,8 +7114,10 @@ phutil_register_library_map(array( 'PhabricatorPeopleNoOwnerDatasource' => 'PhabricatorTypeaheadDatasource', 'PhabricatorPeopleOwnerDatasource' => 'PhabricatorTypeaheadCompositeDatasource', 'PhabricatorPeopleProfileController' => 'PhabricatorPeopleController', - 'PhabricatorPeopleProfileEditController' => 'PhabricatorPeopleController', - 'PhabricatorPeopleProfilePictureController' => 'PhabricatorPeopleController', + 'PhabricatorPeopleProfileEditController' => 'PhabricatorPeopleProfileController', + 'PhabricatorPeopleProfilePanelEngine' => 'PhabricatorProfilePanelEngine', + 'PhabricatorPeopleProfilePictureController' => 'PhabricatorPeopleProfileController', + 'PhabricatorPeopleProfileViewController' => 'PhabricatorPeopleProfileController', 'PhabricatorPeopleQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorPeopleRenameController' => 'PhabricatorPeopleController', 'PhabricatorPeopleSearchEngine' => 'PhabricatorApplicationSearchEngine', @@ -7198,6 +7232,7 @@ phutil_register_library_map(array( ), 'PhabricatorProfilePanelConfigurationQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorProfilePanelConfigurationTransaction' => 'PhabricatorApplicationTransaction', + 'PhabricatorProfilePanelConfigurationTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorProfilePanelEditEngine' => 'PhabricatorEditEngine', 'PhabricatorProfilePanelEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorProfilePanelEngine' => 'Phobject', @@ -7209,12 +7244,10 @@ phutil_register_library_map(array( 'PhabricatorFlaggableInterface', 'PhabricatorPolicyInterface', 'PhabricatorExtendedPolicyInterface', - 'PhabricatorSubscribableInterface', 'PhabricatorCustomFieldInterface', 'PhabricatorDestructibleInterface', 'PhabricatorFulltextInterface', 'PhabricatorConduitResultInterface', - 'PhabricatorProfilePanelInterface', ), 'PhabricatorProjectAddHeraldAction' => 'PhabricatorProjectHeraldAction', 'PhabricatorProjectApplication' => 'PhabricatorApplication', @@ -7223,6 +7256,7 @@ phutil_register_library_map(array( 'PhabricatorProjectBoardImportController' => 'PhabricatorProjectBoardController', 'PhabricatorProjectBoardReorderController' => 'PhabricatorProjectBoardController', 'PhabricatorProjectBoardViewController' => 'PhabricatorProjectBoardController', + 'PhabricatorProjectColorsConfigOptionType' => 'PhabricatorConfigJSONOptionType', 'PhabricatorProjectColumn' => array( 'PhabricatorProjectDAO', 'PhabricatorApplicationTransactionInterface', @@ -7260,10 +7294,13 @@ phutil_register_library_map(array( 'PhabricatorProjectEditController' => 'PhabricatorProjectController', 'PhabricatorProjectEditEngine' => 'PhabricatorEditEngine', 'PhabricatorProjectEditPictureController' => 'PhabricatorProjectController', - 'PhabricatorProjectFeedController' => 'PhabricatorProjectController', 'PhabricatorProjectFulltextEngine' => 'PhabricatorFulltextEngine', 'PhabricatorProjectHeraldAction' => 'HeraldAction', + 'PhabricatorProjectHeraldAdapter' => 'HeraldAdapter', + 'PhabricatorProjectHeraldFieldGroup' => 'HeraldFieldGroup', + 'PhabricatorProjectHistoryController' => 'PhabricatorProjectController', 'PhabricatorProjectIconSet' => 'PhabricatorIconSet', + 'PhabricatorProjectIconsConfigOptionType' => 'PhabricatorConfigJSONOptionType', 'PhabricatorProjectListController' => 'PhabricatorProjectController', 'PhabricatorProjectListView' => 'AphrontView', 'PhabricatorProjectLockController' => 'PhabricatorProjectController', @@ -7273,12 +7310,14 @@ phutil_register_library_map(array( 'PhabricatorProjectLogicalUserDatasource' => 'PhabricatorTypeaheadCompositeDatasource', 'PhabricatorProjectLogicalViewerDatasource' => 'PhabricatorTypeaheadDatasource', 'PhabricatorProjectMaterializedMemberEdgeType' => 'PhabricatorEdgeType', + 'PhabricatorProjectMemberListView' => 'PhabricatorProjectUserListView', 'PhabricatorProjectMemberOfProjectEdgeType' => 'PhabricatorEdgeType', + 'PhabricatorProjectMembersAddController' => 'PhabricatorProjectController', 'PhabricatorProjectMembersDatasource' => 'PhabricatorTypeaheadCompositeDatasource', - 'PhabricatorProjectMembersEditController' => 'PhabricatorProjectController', 'PhabricatorProjectMembersPolicyRule' => 'PhabricatorPolicyRule', 'PhabricatorProjectMembersProfilePanel' => 'PhabricatorProfilePanel', 'PhabricatorProjectMembersRemoveController' => 'PhabricatorProjectController', + 'PhabricatorProjectMembersViewController' => 'PhabricatorProjectController', 'PhabricatorProjectMilestonesController' => 'PhabricatorProjectController', 'PhabricatorProjectMoveController' => 'PhabricatorProjectController', 'PhabricatorProjectNameContextFreeGrammar' => 'PhutilContextFreeGrammar', @@ -7289,6 +7328,7 @@ phutil_register_library_map(array( 'PhabricatorProjectPHIDResolver' => 'PhabricatorPHIDResolver', 'PhabricatorProjectPanelController' => 'PhabricatorProjectController', 'PhabricatorProjectProfileController' => 'PhabricatorProjectController', + 'PhabricatorProjectProfilePanelEngine' => 'PhabricatorProfilePanelEngine', 'PhabricatorProjectProjectHasMemberEdgeType' => 'PhabricatorEdgeType', 'PhabricatorProjectProjectHasObjectEdgeType' => 'PhabricatorEdgeType', 'PhabricatorProjectProjectPHIDType' => 'PhabricatorPHIDType', @@ -7297,6 +7337,8 @@ phutil_register_library_map(array( 'PhabricatorProjectSchemaSpec' => 'PhabricatorConfigSchemaSpec', 'PhabricatorProjectSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorProjectSearchField' => 'PhabricatorSearchTokenizerField', + 'PhabricatorProjectSilenceController' => 'PhabricatorProjectController', + 'PhabricatorProjectSilencedEdgeType' => 'PhabricatorEdgeType', 'PhabricatorProjectSlug' => 'PhabricatorProjectDAO', 'PhabricatorProjectStandardCustomField' => array( 'PhabricatorProjectCustomField', @@ -7308,12 +7350,13 @@ phutil_register_library_map(array( 'PhabricatorProjectTransaction' => 'PhabricatorApplicationTransaction', 'PhabricatorProjectTransactionEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorProjectTransactionQuery' => 'PhabricatorApplicationTransactionQuery', - 'PhabricatorProjectTypeConfigOptionType' => 'PhabricatorConfigJSONOptionType', 'PhabricatorProjectUIEventListener' => 'PhabricatorEventListener', 'PhabricatorProjectUpdateController' => 'PhabricatorProjectController', 'PhabricatorProjectUserFunctionDatasource' => 'PhabricatorTypeaheadCompositeDatasource', + 'PhabricatorProjectUserListView' => 'AphrontView', 'PhabricatorProjectViewController' => 'PhabricatorProjectController', 'PhabricatorProjectWatchController' => 'PhabricatorProjectController', + 'PhabricatorProjectWatcherListView' => 'PhabricatorProjectUserListView', 'PhabricatorProjectWorkboardProfilePanel' => 'PhabricatorProfilePanel', 'PhabricatorProjectsEditEngineExtension' => 'PhabricatorEditEngineExtension', 'PhabricatorProjectsEditField' => 'PhabricatorTokenizerEditField', diff --git a/src/applications/badges/storage/PhabricatorBadgesBadge.php b/src/applications/badges/storage/PhabricatorBadgesBadge.php index 29cccb9f44..254b02a6eb 100644 --- a/src/applications/badges/storage/PhabricatorBadgesBadge.php +++ b/src/applications/badges/storage/PhabricatorBadgesBadge.php @@ -185,10 +185,6 @@ final class PhabricatorBadgesBadge extends PhabricatorBadgesDAO return true; } - public function shouldAllowSubscription($phid) { - return true; - } - /* -( PhabricatorTokenReceiverInterface )---------------------------------- */ diff --git a/src/applications/base/PhabricatorApplication.php b/src/applications/base/PhabricatorApplication.php index 4fc3e10314..0ed4917800 100644 --- a/src/applications/base/PhabricatorApplication.php +++ b/src/applications/base/PhabricatorApplication.php @@ -641,6 +641,7 @@ abstract class PhabricatorApplication return array( '(?Pview)/(?P[^/]+)/' => $controller, '(?Phide)/(?P[^/]+)/' => $controller, + '(?Pdefault)/(?P[^/]+)/' => $controller, '(?Pconfigure)/' => $controller, '(?Preorder)/' => $controller, '(?Pedit)/'.$edit_route => $controller, diff --git a/src/applications/calendar/storage/PhabricatorCalendarEvent.php b/src/applications/calendar/storage/PhabricatorCalendarEvent.php index 1b4c1a760c..36aa905b3e 100644 --- a/src/applications/calendar/storage/PhabricatorCalendarEvent.php +++ b/src/applications/calendar/storage/PhabricatorCalendarEvent.php @@ -535,10 +535,6 @@ final class PhabricatorCalendarEvent extends PhabricatorCalendarDAO return true; } - public function shouldAllowSubscription($phid) { - return true; - } - /* -( PhabricatorTokenReceiverInterface )---------------------------------- */ diff --git a/src/applications/celerity/CeleritySpriteGenerator.php b/src/applications/celerity/CeleritySpriteGenerator.php index b5c1ae1b9e..55346c915c 100644 --- a/src/applications/celerity/CeleritySpriteGenerator.php +++ b/src/applications/celerity/CeleritySpriteGenerator.php @@ -86,38 +86,6 @@ final class CeleritySpriteGenerator extends Phobject { return $sheet; } - public function buildProjectsSheet() { - $icons = $this->getDirectoryList('projects_1x'); - $scales = array( - '1x' => 1, - '2x' => 2, - ); - $template = id(new PhutilSprite()) - ->setSourceSize(50, 50); - - $sprites = array(); - $prefix = 'projects-'; - foreach ($icons as $icon) { - $sprite = id(clone $template) - ->setName($prefix.$icon) - ->setTargetCSS('.'.$prefix.$icon); - - foreach ($scales as $scale_key => $scale) { - $path = $this->getPath('projects_'.$scale_key.'/'.$icon.'.png'); - $sprite->setSourceFile($path, $scale); - } - $sprites[] = $sprite; - } - - $sheet = $this->buildSheet('projects', true); - $sheet->setScales($scales); - foreach ($sprites as $sprite) { - $sheet->addSprite($sprite); - } - - return $sheet; - } - public function buildLoginSheet() { $icons = $this->getDirectoryList('login_1x'); $scales = array( @@ -150,33 +118,6 @@ final class CeleritySpriteGenerator extends Phobject { return $sheet; } - public function buildMainHeaderSheet() { - $gradients = $this->getDirectoryList('main_header'); - $template = new PhutilSprite(); - - $sprites = array(); - foreach ($gradients as $gradient) { - $path = $this->getPath('main_header/'.$gradient.'.png'); - $sprite = id(clone $template) - ->setName('main-header-'.$gradient) - ->setSourceFile($path) - ->setTargetCSS('.phui-theme-'.$gradient. - ' .phabricator-main-menu-background'); - $sprite->setSourceSize(6, 44); - $sprites[] = $sprite; - } - - $sheet = $this->buildSheet('main-header', - false, - PhutilSpriteSheet::TYPE_REPEAT_X); - - foreach ($sprites as $sprite) { - $sheet->addSprite($sprite); - } - - return $sheet; - } - private function getPath($to_path = null) { $root = dirname(phutil_get_library_root('phabricator')); return $root.'/resources/sprite/'.$to_path; diff --git a/src/applications/celerity/postprocessor/CelerityDefaultPostprocessor.php b/src/applications/celerity/postprocessor/CelerityDefaultPostprocessor.php index 7c230d9869..94246e23c7 100644 --- a/src/applications/celerity/postprocessor/CelerityDefaultPostprocessor.php +++ b/src/applications/celerity/postprocessor/CelerityDefaultPostprocessor.php @@ -191,6 +191,21 @@ final class CelerityDefaultPostprocessor // Background color for "dark" themes. 'page.background.dark' => '#ebecee', + // This is the base background color. + 'menu.profile.background' => '#525867', + 'menu.profile.background.hover' => '#464b58', + 'menu.profile.background.selected' => '#393d48', + + 'menu.profile.text' => '#c6c7cb', + 'menu.profile.text.selected' => '#ffffff', + 'menu.profile.icon.disabled' => '#b9bcc2', + + 'menu.main.height' => '44px', + + 'menu.profile.width' => '240px', + 'menu.profile.width.collapsed' => '88px', + 'menu.profile.item.height' => '46px', + ); } diff --git a/src/applications/config/option/PhabricatorUIConfigOptions.php b/src/applications/config/option/PhabricatorUIConfigOptions.php index 84a7b4be6b..6b94cf1795 100644 --- a/src/applications/config/option/PhabricatorUIConfigOptions.php +++ b/src/applications/config/option/PhabricatorUIConfigOptions.php @@ -20,15 +20,18 @@ final class PhabricatorUIConfigOptions } public function getOptions() { - $manifest = PHUIIconView::getSheetManifest('main-header'); $custom_header_example = PhabricatorCustomHeaderConfigType::getExampleConfig(); $experimental_link = 'https://secure.phabricator.com/T4214'; - $options = array(); - foreach (array_keys($manifest) as $sprite_name) { - $key = substr($sprite_name, strlen('main-header-')); - $options[$key] = $key; - } + $options = array( + 'blindigo' => 'blindigo', + 'light' => 'light', + 'red' => 'red', + 'blue' => 'blue', + 'green' => 'green', + 'indigo' => 'indigo', + 'dark' => 'dark', + ); $example = <<getName(); @@ -33,12 +34,16 @@ final class PhabricatorConfigDatabaseSchema PhabricatorConfigStorageSchema $expect) { $issues = array(); - if ($this->getCharacterSet() != $expect->getCharacterSet()) { - $issues[] = self::ISSUE_CHARSET; - } + if ($this->getAccessDenied()) { + $issues[] = self::ISSUE_ACCESSDENIED; + } else { + if ($this->getCharacterSet() != $expect->getCharacterSet()) { + $issues[] = self::ISSUE_CHARSET; + } - if ($this->getCollation() != $expect->getCollation()) { - $issues[] = self::ISSUE_COLLATION; + if ($this->getCollation() != $expect->getCollation()) { + $issues[] = self::ISSUE_COLLATION; + } } return $issues; @@ -68,4 +73,13 @@ final class PhabricatorConfigDatabaseSchema return $this->characterSet; } + public function setAccessDenied($access_denied) { + $this->accessDenied = $access_denied; + return $this; + } + + public function getAccessDenied() { + return $this->accessDenied; + } + } diff --git a/src/applications/config/schema/PhabricatorConfigSchemaQuery.php b/src/applications/config/schema/PhabricatorConfigSchemaQuery.php index c1e94619ce..ca9b44cc07 100644 --- a/src/applications/config/schema/PhabricatorConfigSchemaQuery.php +++ b/src/applications/config/schema/PhabricatorConfigSchemaQuery.php @@ -47,6 +47,25 @@ final class PhabricatorConfigSchemaQuery extends Phobject { $databases); $database_info = ipull($database_info, null, 'SCHEMA_NAME'); + // Find databases which exist, but which the user does not have permission + // to see. + $invisible_databases = array(); + foreach ($databases as $database_name) { + if (isset($database_info[$database_name])) { + continue; + } + + try { + queryfx($conn, 'SHOW TABLES IN %T', $database_name); + } catch (AphrontAccessDeniedQueryException $ex) { + // This database exists, the user just doesn't have permission to + // see it. + $invisible_databases[] = $database_name; + } catch (AphrontSchemaQueryException $ex) { + // This database is legitimately missing. + } + } + $sql = array(); foreach ($tables as $table) { $sql[] = qsprintf( @@ -148,6 +167,13 @@ final class PhabricatorConfigSchemaQuery extends Phobject { $server_schema->addDatabase($database_schema); } + foreach ($invisible_databases as $database_name) { + $server_schema->addDatabase( + id(new PhabricatorConfigDatabaseSchema()) + ->setName($database_name) + ->setAccessDenied(true)); + } + return $server_schema; } @@ -194,6 +220,7 @@ final class PhabricatorConfigSchemaQuery extends Phobject { if (!$actual_database) { $actual_database = $expect_database->newEmptyClone(); } + if (!$expect_database) { $expect_database = $actual_database->newEmptyClone(); } diff --git a/src/applications/config/schema/PhabricatorConfigStorageSchema.php b/src/applications/config/schema/PhabricatorConfigStorageSchema.php index 74856053e4..706be80568 100644 --- a/src/applications/config/schema/PhabricatorConfigStorageSchema.php +++ b/src/applications/config/schema/PhabricatorConfigStorageSchema.php @@ -17,6 +17,7 @@ abstract class PhabricatorConfigStorageSchema extends Phobject { const ISSUE_SUBFAIL = 'subfail'; const ISSUE_AUTOINCREMENT = 'autoincrement'; const ISSUE_UNKNOWN = 'unknown'; + const ISSUE_ACCESSDENIED = 'accessdenied'; const STATUS_OKAY = 'okay'; const STATUS_WARN = 'warn'; @@ -130,6 +131,8 @@ abstract class PhabricatorConfigStorageSchema extends Phobject { return pht('Column has Wrong Autoincrement'); case self::ISSUE_UNKNOWN: return pht('Column Has No Specification'); + case self::ISSUE_ACCESSDENIED: + return pht('Access Denied'); default: throw new Exception(pht('Unknown schema issue "%s"!', $issue)); } @@ -175,6 +178,7 @@ abstract class PhabricatorConfigStorageSchema extends Phobject { public static function getIssueStatus($issue) { switch ($issue) { case self::ISSUE_MISSING: + case self::ISSUE_ACCESSDENIED: case self::ISSUE_SURPLUS: case self::ISSUE_NULLABLE: case self::ISSUE_SUBFAIL: diff --git a/src/applications/countdown/storage/PhabricatorCountdown.php b/src/applications/countdown/storage/PhabricatorCountdown.php index 8753c66223..1a864907eb 100644 --- a/src/applications/countdown/storage/PhabricatorCountdown.php +++ b/src/applications/countdown/storage/PhabricatorCountdown.php @@ -74,10 +74,6 @@ final class PhabricatorCountdown extends PhabricatorCountdownDAO return true; } - public function shouldAllowSubscription($phid) { - return true; - } - /* -( PhabricatorApplicationTransactionInterface )------------------------- */ diff --git a/src/applications/differential/controller/DifferentialChangesetViewController.php b/src/applications/differential/controller/DifferentialChangesetViewController.php index 3f08ce4883..01bdd395a7 100644 --- a/src/applications/differential/controller/DifferentialChangesetViewController.php +++ b/src/applications/differential/controller/DifferentialChangesetViewController.php @@ -400,16 +400,23 @@ final class DifferentialChangesetViewController extends DifferentialController { private function loadCoverage(DifferentialChangeset $changeset) { $target_phids = $changeset->getDiff()->getBuildTargetPHIDs(); if (!$target_phids) { - return array(); + return null; } $unit = id(new HarbormasterBuildUnitMessage())->loadAllWhere( 'buildTargetPHID IN (%Ls)', $target_phids); + if (!$unit) { + return null; + } + $coverage = array(); foreach ($unit as $message) { - $test_coverage = $message->getProperty('coverage', array()); + $test_coverage = $message->getProperty('coverage'); + if ($test_coverage === null) { + continue; + } $coverage_data = idx($test_coverage, $changeset->getFileName()); if (!strlen($coverage_data)) { continue; @@ -417,6 +424,10 @@ final class DifferentialChangesetViewController extends DifferentialController { $coverage[] = $coverage_data; } + if (!$coverage) { + return null; + } + return ArcanistUnitTestResult::mergeCoverage($coverage); } diff --git a/src/applications/differential/storage/DifferentialRevision.php b/src/applications/differential/storage/DifferentialRevision.php index e534ad9ca7..ff72b46de7 100644 --- a/src/applications/differential/storage/DifferentialRevision.php +++ b/src/applications/differential/storage/DifferentialRevision.php @@ -485,10 +485,6 @@ final class DifferentialRevision extends DifferentialDAO return true; } - public function shouldAllowSubscription($phid) { - return true; - } - /* -( PhabricatorCustomFieldInterface )------------------------------------ */ diff --git a/src/applications/diffusion/conduit/DiffusionFileContentQueryConduitAPIMethod.php b/src/applications/diffusion/conduit/DiffusionFileContentQueryConduitAPIMethod.php index 8088aa66b8..10e4d00b83 100644 --- a/src/applications/diffusion/conduit/DiffusionFileContentQueryConduitAPIMethod.php +++ b/src/applications/diffusion/conduit/DiffusionFileContentQueryConduitAPIMethod.php @@ -39,14 +39,20 @@ final class DiffusionFileContentQueryConduitAPIMethod $file_query->setByteLimit($byte_limit); } - $content = $file_query->execute(); + $file = $file_query->execute(); $too_slow = (bool)$file_query->getExceededTimeLimit(); $too_huge = (bool)$file_query->getExceededByteLimit(); $file_phid = null; if (!$too_slow && !$too_huge) { - $file = $this->newFile($drequest, $content); + $repository = $drequest->getRepository(); + $repository_phid = $repository->getPHID(); + + $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); + $file->attachToObject($repository_phid); + unset($unguarded); + $file_phid = $file->getPHID(); } @@ -57,26 +63,4 @@ final class DiffusionFileContentQueryConduitAPIMethod ); } - private function newFile(DiffusionRequest $drequest, $content) { - $path = $drequest->getPath(); - $name = basename($path); - - $repository = $drequest->getRepository(); - $repository_phid = $repository->getPHID(); - - $file = PhabricatorFile::buildFromFileDataOrHash( - $content, - array( - 'name' => $name, - 'ttl' => time() + phutil_units('48 hours in seconds'), - 'viewPolicy' => PhabricatorPolicies::POLICY_NOONE, - )); - - $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); - $file->attachToObject($repository_phid); - unset($unguarded); - - return $file; - } - } diff --git a/src/applications/diffusion/query/filecontent/DiffusionFileContentQuery.php b/src/applications/diffusion/query/filecontent/DiffusionFileContentQuery.php index 3ea0e12ba1..df14b49235 100644 --- a/src/applications/diffusion/query/filecontent/DiffusionFileContentQuery.php +++ b/src/applications/diffusion/query/filecontent/DiffusionFileContentQuery.php @@ -54,23 +54,46 @@ abstract class DiffusionFileContentQuery extends DiffusionQuery { $future->setStdoutSizeLimit($byte_limit + 1); } + $drequest = $this->getRequest(); + + $name = basename($drequest->getPath()); + $ttl = PhabricatorTime::getNow() + phutil_units('48 hours in seconds'); + try { - $file_content = $this->resolveFileContentFuture($future); + $threshold = PhabricatorFileStorageEngine::getChunkThreshold(); + $future->setReadBufferSize($threshold); + + $source = id(new PhabricatorExecFutureFileUploadSource()) + ->setName($name) + ->setTTL($ttl) + ->setViewPolicy(PhabricatorPolicies::POLICY_NOONE) + ->setExecFuture($future); + + $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); + $file = $source->uploadFile(); + unset($unguarded); + } catch (CommandException $ex) { if (!$future->getWasKilledByTimeout()) { throw $ex; } $this->didHitTimeLimit = true; - $file_content = null; + $file = null; } - if ($byte_limit && (strlen($file_content) > $byte_limit)) { + if ($byte_limit && ($file->getByteSize() > $byte_limit)) { $this->didHitByteLimit = true; - $file_content = null; + + $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); + id(new PhabricatorDestructionEngine()) + ->destroyObject($file); + unset($unguarded); + + $file = null; } - return $file_content; + return $file; } } diff --git a/src/applications/files/applicationpanel/PhabricatorFilesApplicationStorageEnginePanel.php b/src/applications/files/applicationpanel/PhabricatorFilesApplicationStorageEnginePanel.php index c9a9bad51e..0d3fdc46cc 100644 --- a/src/applications/files/applicationpanel/PhabricatorFilesApplicationStorageEnginePanel.php +++ b/src/applications/files/applicationpanel/PhabricatorFilesApplicationStorageEnginePanel.php @@ -26,11 +26,15 @@ final class PhabricatorFilesApplicationStorageEnginePanel $rows = array(); $rowc = array(); foreach ($engines as $key => $engine) { - $limited = $no; + if ($engine->isTestEngine()) { + continue; + } + $limit = null; if ($engine->hasFilesizeLimit()) { - $limited = $yes; $limit = phutil_format_bytes($engine->getFilesizeLimit()); + } else { + $limit = pht('Unlimited'); } if ($engine->canWriteFiles()) { @@ -39,12 +43,6 @@ final class PhabricatorFilesApplicationStorageEnginePanel $writable = $no; } - if ($engine->isTestEngine()) { - $test = $yes; - } else { - $test = $no; - } - if (isset($writable_engines[$key]) || isset($chunk_engines[$key])) { $rowc[] = 'highlighted'; } else { @@ -54,9 +52,7 @@ final class PhabricatorFilesApplicationStorageEnginePanel $rows[] = array( $key, get_class($engine), - $test, $writable, - $limited, $limit, ); } @@ -67,9 +63,7 @@ final class PhabricatorFilesApplicationStorageEnginePanel array( pht('Key'), pht('Class'), - pht('Unit Test'), pht('Writable'), - pht('Has Limit'), pht('Limit'), )) ->setRowClasses($rowc) @@ -78,8 +72,6 @@ final class PhabricatorFilesApplicationStorageEnginePanel '', 'wide', '', - '', - '', 'n', )); diff --git a/src/applications/files/builtin/PhabricatorFilesBuiltinFile.php b/src/applications/files/builtin/PhabricatorFilesBuiltinFile.php new file mode 100644 index 0000000000..f1ad3da197 --- /dev/null +++ b/src/applications/files/builtin/PhabricatorFilesBuiltinFile.php @@ -0,0 +1,9 @@ +icon = $icon; + return $this; + } + + public function getIcon() { + return $this->icon; + } + + public function setColor($color) { + $this->color = $color; + return $this; + } + + public function getColor() { + return $this->color; + } + + public function getBuiltinFileKey() { + $icon = $this->getIcon(); + $color = $this->getColor(); + $desc = "compose(icon={$icon}, color={$color})"; + $hash = PhabricatorHash::digestToLength($desc, 40); + return "builtin:{$hash}"; + } + + public function getBuiltinDisplayName() { + $icon = $this->getIcon(); + $color = $this->getColor(); + return "{$icon}-{$color}.png"; + } + + public function loadBuiltinFileData() { + return $this->composeImage($this->getColor(), $this->getIcon()); + } + + public static function getAllIcons() { + $root = dirname(phutil_get_library_root('phabricator')); + $root = $root.'/resources/builtin/projects/'; + + $quips = self::getIconQuips(); + + $map = array(); + $list = Filesystem::listDirectory($root, $include_hidden = false); + foreach ($list as $file) { + $short = preg_replace('/\.png$/', '', $file); + + $map[$short] = array( + 'path' => $root.$file, + 'quip' => idx($quips, $short, $short), + ); + } + + return $map; + } + + public static function getAllColors() { + $colors = id(new CelerityResourceTransformer()) + ->getCSSVariableMap(); + + $colors = array_select_keys( + $colors, + array( + 'red', + 'orange', + 'yellow', + 'green', + 'blue', + 'sky', + 'indigo', + 'violet', + 'pink', + 'charcoal', + 'backdrop', + )); + + $quips = self::getColorQuips(); + + $map = array(); + foreach ($colors as $name => $color) { + $map[$name] = array( + 'color' => $color, + 'quip' => idx($quips, $name, $name), + ); + } + + return $map; + } + + private function composeImage($color, $icon) { + $color_map = self::getAllColors(); + $color = idx($color_map, $color); + if (!$color) { + $fallback = 'backdrop'; + $color = idx($color_map, $fallback); + if (!$color) { + throw new Exception( + pht( + 'Fallback compose color ("%s") does not exist!', + $fallback)); + } + } + + $color_hex = idx($color, 'color'); + $color_const = hexdec(trim($color_hex, '#')); + + $icon_map = self::getAllIcons(); + $icon = idx($icon_map, $icon); + if (!$icon) { + $fallback = 'fa-umbrella'; + $icon = idx($icon_map, $fallback); + if (!$icon) { + throw new Exception( + pht( + 'Fallback compose icon ("%s") does not exist!', + $fallback)); + } + } + + $path = idx($icon, 'path'); + $data = Filesystem::readFile($path); + + $icon_img = imagecreatefromstring($data); + + $canvas = imagecreatetruecolor(200, 200); + imagefill($canvas, 0, 0, $color_const); + imagecopy($canvas, $icon_img, 0, 0, 0, 0, 200, 200); + + return PhabricatorImageTransformer::saveImageDataInAnyFormat( + $canvas, + 'image/png'); + } + + private static function getIconQuips() { + return array( + 'fa-android' => pht('Friendly Robot'), + 'fa-apple' => pht('Friendly Fruit'), + 'fa-beer' => pht('Liquid Carbs'), + 'fa-bomb' => pht('Boom!'), + 'fa-book' => pht('Read Me'), + 'fa-briefcase' => pht('Briefcase'), + 'fa-bug' => pht('Bug'), + 'fa-building' => pht('Company'), + 'fa-calendar' => pht('Deadline'), + 'fa-camera-retro' => pht('Leica Enth1usiast'), + 'fa-chrome' => pht('Shiny'), + 'fa-cloud' => pht('The Cloud'), + 'fa-coffee' => pht('Go Juice'), + 'fa-comments' => pht('Cartoon Captions'), + 'fa-credit-card' => pht('Accounting'), + 'fa-database' => pht('Stack of Pancakes'), + 'fa-desktop' => pht('Cardboard Box'), + 'fa-diamond' => pht('Isometric-Hexoctahedral'), + 'fa-empire' => pht('Bad Guys'), + 'fa-envelope' => pht('Communication'), + 'fa-facebook' => pht('College Site'), + 'fa-fax' => pht('Communication Device'), + 'fa-film' => pht('Physical Film'), + 'fa-firefox' => pht('Blake Ross'), + 'fa-flag-checkered' => pht('Goal'), + 'fa-flask' => pht('Experimental'), + 'fa-folder' => pht('Folder'), + 'fa-gamepad' => pht('Half-Life 3 Confirmed'), + 'fa-gears' => pht('Mechanical'), + 'fa-google' => pht('Car Company'), + 'fa-hand-peace-o' => pht('Peace'), + 'fa-hashtag' => pht('Not Slack'), + 'fa-heart' => pht('Myocardial Infarction'), + 'fa-internet-explorer' => pht('Now Just Edge'), + 'fa-key' => pht('Primitive Security'), + 'fa-legal' => pht('Hired Protection'), + 'fa-linux' => pht('M\`Lady'), + 'fa-lock' => pht('Policy'), + 'fa-microphone' => pht('Podcasting'), + 'fa-mobile' => pht('Tiny Pocket Cat Meme Machine'), + 'fa-money' => pht('1 of 99 Problems'), + 'fa-phone' => pht('Grandma Uses This'), + 'fa-pie-chart' => pht('Not Actually Edible'), + 'fa-rebel' => pht('Good Guys'), + 'fa-reddit-alien' => pht('Updoot In 5 Seconds'), + 'fa-safari' => pht('Fruit Exploration'), + 'fa-search' => pht('Dust Detector'), + 'fa-server' => pht('Heating Units'), + 'fa-shopping-cart' => pht('Buy Stuff'), + 'fa-sitemap' => pht('Sitemap'), + 'fa-star' => pht('The More You Know'), + 'fa-tablet' => pht('Cellular Telephone For Giants'), + 'fa-tag' => pht('You\'re It'), + 'fa-tags' => pht('Tags'), + 'fa-trash-o' => pht('Garbage'), + 'fa-truck' => pht('Release'), + 'fa-twitter' => pht('Bird Stencil'), + 'fa-umbrella' => pht('An Umbrella'), + 'fa-university' => pht('School'), + 'fa-user-secret' => pht('Shhh'), + 'fa-user' => pht('Individual'), + 'fa-users' => pht('Team'), + 'fa-warning' => pht('No Caution Required, Everything Looks Safe'), + 'fa-wheelchair' => pht('Accessability'), + 'fa-windows' => pht('Windows'), + ); + } + + private static function getColorQuips() { + return array( + 'red' => pht('Verbillion'), + 'orange' => pht('Navel Orange'), + 'yellow' => pht('Prim Goldenrod'), + 'green' => pht('Lustrous Verdant'), + 'blue' => pht('Tropical Deep'), + 'sky' => pht('Wide Open Sky'), + 'indigo' => pht('Pleated Khaki'), + 'violet' => pht('Aged Merlot'), + 'pink' => pht('Easter Bunny'), + 'charcoal' => pht('Gemstone'), + 'backdrop' => pht('Driven Snow'), + ); + } + +} diff --git a/src/applications/files/builtin/PhabricatorFilesOnDiskBuiltinFile.php b/src/applications/files/builtin/PhabricatorFilesOnDiskBuiltinFile.php new file mode 100644 index 0000000000..b32ea6d39e --- /dev/null +++ b/src/applications/files/builtin/PhabricatorFilesOnDiskBuiltinFile.php @@ -0,0 +1,56 @@ +name = $name; + return $this; + } + + public function getName() { + if ($this->name === null) { + throw new PhutilInvalidStateException('setName'); + } + + return $this->name; + } + + public function getBuiltinDisplayName() { + return $this->getName(); + } + + public function getBuiltinFileKey() { + $name = $this->getName(); + $desc = "disk(name={$name})"; + $hash = PhabricatorHash::digestToLength($desc, 40); + return "builtin:{$hash}"; + } + + public function loadBuiltinFileData() { + $name = $this->getName(); + + $available = $this->getAllBuiltinFiles(); + if (empty($available[$name])) { + throw new Exception(pht('Builtin "%s" does not exist!', $name)); + } + + return Filesystem::readFile($available[$name]); + } + + private function getAllBuiltinFiles() { + $root = dirname(phutil_get_library_root('phabricator')); + $root = $root.'/resources/builtin/'; + + $map = array(); + $list = Filesystem::listDirectory($root, $include_hidden = false); + foreach ($list as $file) { + $map[$file] = $root.$file; + } + + return $map; + } + +} diff --git a/src/applications/files/controller/PhabricatorFileComposeController.php b/src/applications/files/controller/PhabricatorFileComposeController.php index de5a6757a4..404cf44aca 100644 --- a/src/applications/files/controller/PhabricatorFileComposeController.php +++ b/src/applications/files/controller/PhabricatorFileComposeController.php @@ -6,21 +6,8 @@ final class PhabricatorFileComposeController public function handleRequest(AphrontRequest $request) { $viewer = $request->getViewer(); - $colors = array( - 'red' => pht('Verbillion'), - 'orange' => pht('Navel Orange'), - 'yellow' => pht('Prim Goldenrod'), - 'green' => pht('Lustrous Verdant'), - 'blue' => pht('Tropical Deep'), - 'sky' => pht('Wide Open Sky'), - 'indigo' => pht('Pleated Khaki'), - 'violet' => pht('Aged Merlot'), - 'pink' => pht('Easter Bunny'), - 'charcoal' => pht('Gemstone'), - 'backdrop' => pht('Driven Snow'), - ); - - $manifest = PHUIIconView::getSheetManifest(PHUIIconView::SPRITE_PROJECTS); + $color_map = PhabricatorFilesComposeIconBuiltinFile::getAllColors(); + $icon_map = $this->getIconMap(); if ($request->isFormPost()) { $project_phid = $request->getStr('projectPHID'); @@ -37,42 +24,27 @@ final class PhabricatorFileComposeController if (!$project) { return new Aphront404Response(); } - $icon = $project->getIcon(); - $color = $project->getColor(); - switch ($color) { - case 'grey': - $color = 'charcoal'; - break; - case 'checkered': - $color = 'backdrop'; - break; - } - } else { - $icon = $request->getStr('icon'); - $color = $request->getStr('color'); } - if (!isset($colors[$color]) || !isset($manifest['projects-'.$icon])) { - return new Aphront404Response(); - } + $icon = $request->getStr('icon'); + $color = $request->getStr('color'); - $root = dirname(phutil_get_library_root('phabricator')); - $icon_file = $root.'/resources/sprite/projects_2x/'.$icon.'.png'; - $icon_data = Filesystem::readFile($icon_file); + $composer = id(new PhabricatorFilesComposeIconBuiltinFile()) + ->setIcon($icon) + ->setColor($color); - - $data = $this->composeImage($color, $icon_data); + $data = $composer->loadBuiltinFileData(); $file = PhabricatorFile::buildFromFileDataOrHash( $data, array( - 'name' => 'project.png', + 'name' => $composer->getBuiltinDisplayName(), 'profile' => true, 'canCDN' => true, )); if ($project_phid) { - $edit_uri = '/project/profile/'.$project->getID().'/'; + $edit_uri = '/project/history/'.$project->getID().'/'; $xactions = array(); $xactions[] = id(new PhabricatorProjectTransaction()) @@ -97,14 +69,15 @@ final class PhabricatorFileComposeController } } - $value_color = head_key($colors); - $value_icon = head_key($manifest); - $value_icon = substr($value_icon, strlen('projects-')); + $value_color = head_key($color_map); + $value_icon = head_key($icon_map); require_celerity_resource('people-profile-css'); $buttons = array(); - foreach ($colors as $color => $name) { + foreach ($color_map as $color => $info) { + $quip = idx($info, 'quip'); + $buttons[] = javelin_tag( 'button', array( @@ -113,116 +86,17 @@ final class PhabricatorFileComposeController 'style' => 'margin: 0 8px 8px 0', 'meta' => array( 'color' => $color, - 'tip' => $name, + 'tip' => $quip, ), ), id(new PHUIIconView()) ->addClass('compose-background-'.$color)); } - $sort_these_first = array( - 'projects-fa-briefcase', - 'projects-fa-tags', - 'projects-fa-folder', - 'projects-fa-group', - 'projects-fa-bug', - 'projects-fa-trash-o', - 'projects-fa-calendar', - 'projects-fa-flag-checkered', - 'projects-fa-envelope', - 'projects-fa-truck', - 'projects-fa-lock', - 'projects-fa-umbrella', - 'projects-fa-cloud', - 'projects-fa-building', - 'projects-fa-credit-card', - 'projects-fa-flask', - ); - - $manifest = array_select_keys( - $manifest, - $sort_these_first) - + $manifest; $icons = array(); - - $icon_quips = array( - '8ball' => pht('Take a Risk'), - 'alien' => pht('Foreign Interface'), - 'announce' => pht('Louder is Better'), - 'art' => pht('Unique Snowflake'), - 'award' => pht('Shooting Star'), - 'bacon' => pht('Healthy Vegetables'), - 'bandaid' => pht('Durable Infrastructure'), - 'beer' => pht('Healthy Vegetable Juice'), - 'bomb' => pht('Imminent Success'), - 'briefcase' => pht('Adventure Pack'), - 'bug' => pht('Costumed Egg'), - 'calendar' => pht('Everyone Loves Meetings'), - 'cloud' => pht('Water Cycle'), - 'coffee' => pht('Half-Whip Nonfat Soy Latte'), - 'creditcard' => pht('Expense It'), - 'death' => pht('Calcium Promotes Bone Health'), - 'desktop' => pht('Magical Portal'), - 'dropbox' => pht('Cardboard Box'), - 'education' => pht('Debt'), - 'experimental' => pht('CAUTION: Dangerous Chemicals'), - 'facebook' => pht('Popular Social Network'), - 'facility' => pht('Pollution Solves Problems'), - 'film' => pht('Actual Physical Film'), - 'forked' => pht('You Can\'t Eat Soup'), - 'games' => pht('Serious Business'), - 'ghost' => pht('Haunted'), - 'gift' => pht('Surprise!'), - 'globe' => pht('Scanner Sweep'), - 'golf' => pht('Business Meeting'), - 'heart' => pht('Undergoing a Major Surgery'), - 'intergalactic' => pht('Jupiter'), - 'lock' => pht('Extremely Secret'), - 'mail' => pht('Oragami'), - 'martini' => pht('Healthy Olive Drink'), - 'medical' => pht('Medic!'), - 'mobile' => pht('Cellular Telephone'), - 'music' => pht("\xE2\x99\xAB"), - 'news' => pht('Actual Physical Newspaper'), - 'orgchart' => pht('It\'s Good to be King'), - 'peoples' => pht('Angel and Devil'), - 'piechart' => pht('Actual Physical Pie'), - 'poison' => pht('Healthy Bone Juice'), - 'putabirdonit' => pht('Put a Bird On It'), - 'radiate' => pht('Radiant Beauty'), - 'savings' => pht('Oink Oink'), - 'search' => pht('Sleuthing'), - 'shield' => pht('Royal Crest'), - 'speed' => pht('Slow and Steady'), - 'sprint' => pht('Fire Exit'), - 'star' => pht('The More You Know'), - 'storage' => pht('Stack of Pancakes'), - 'tablet' => pht('Cellular Telephone For Giants'), - 'travel' => pht('Pretty Clearly an Airplane'), - 'twitter' => pht('Bird Stencil'), - 'warning' => pht('No Caution Required, Everything Looks Safe'), - 'whale' => pht('Friendly Walrus'), - 'fa-flask' => pht('Experimental'), - 'fa-briefcase' => pht('Briefcase'), - 'fa-bug' => pht('Bug'), - 'fa-building' => pht('Company'), - 'fa-calendar' => pht('Deadline'), - 'fa-cloud' => pht('The Cloud'), - 'fa-credit-card' => pht('Accounting'), - 'fa-envelope' => pht('Communication'), - 'fa-flag-checkered' => pht('Goal'), - 'fa-folder' => pht('Folder'), - 'fa-group' => pht('Team'), - 'fa-lock' => pht('Policy'), - 'fa-tags' => pht('Tag'), - 'fa-trash-o' => pht('Garbage'), - 'fa-truck' => pht('Release'), - 'fa-umbrella' => pht('An Umbrella'), - ); - - foreach ($manifest as $icon => $spec) { - $icon = substr($icon, strlen('projects-')); + foreach ($icon_map as $icon => $spec) { + $quip = idx($spec, 'quip'); $icons[] = javelin_tag( 'button', @@ -232,12 +106,12 @@ final class PhabricatorFileComposeController 'style' => 'margin: 0 8px 8px 0', 'meta' => array( 'icon' => $icon, - 'tip' => idx($icon_quips, $icon, $icon), + 'tip' => $quip, ), ), id(new PHUIIconView()) - ->setSpriteIcon($icon) - ->setSpriteSheet(PHUIIconView::SPRITE_PROJECTS)); + ->setIconFont($icon) + ->addClass('compose-icon-bg')); } $dialog_id = celerity_generate_unique_node_id(); @@ -248,8 +122,8 @@ final class PhabricatorFileComposeController $preview = id(new PHUIIconView()) ->setID($preview_id) ->addClass('compose-background-'.$value_color) - ->setSpriteIcon($value_icon) - ->setSpriteSheet(PHUIIconView::SPRITE_PROJECTS); + ->setIconFont($value_icon) + ->addClass('compose-icon-bg'); $color_input = javelin_tag( 'input', @@ -318,23 +192,31 @@ final class PhabricatorFileComposeController return id(new AphrontDialogResponse())->setDialog($dialog); } - private function composeImage($color, $icon_data) { - $icon_img = imagecreatefromstring($icon_data); + private function getIconMap() { + $icon_map = PhabricatorFilesComposeIconBuiltinFile::getAllIcons(); - $map = id(new CelerityResourceTransformer()) - ->getCSSVariableMap(); + $first = array( + 'fa-briefcase', + 'fa-tags', + 'fa-folder', + 'fa-group', + 'fa-bug', + 'fa-trash-o', + 'fa-calendar', + 'fa-flag-checkered', + 'fa-envelope', + 'fa-truck', + 'fa-lock', + 'fa-umbrella', + 'fa-cloud', + 'fa-building', + 'fa-credit-card', + 'fa-flask', + ); - $color_string = idx($map, $color, '#ff00ff'); - $color_const = hexdec(trim($color_string, '#')); + $icon_map = array_select_keys($icon_map, $first) + $icon_map; - $canvas = imagecreatetruecolor(100, 100); - imagefill($canvas, 0, 0, $color_const); - - imagecopy($canvas, $icon_img, 0, 0, 0, 0, 100, 100); - - return PhabricatorImageTransformer::saveImageDataInAnyFormat( - $canvas, - 'image/png'); + return $icon_map; } } diff --git a/src/applications/files/storage/PhabricatorFile.php b/src/applications/files/storage/PhabricatorFile.php index f0a5f228e3..7d2780778f 100644 --- a/src/applications/files/storage/PhabricatorFile.php +++ b/src/applications/files/storage/PhabricatorFile.php @@ -961,16 +961,18 @@ final class PhabricatorFile extends PhabricatorFileDAO * Builtins are located in `resources/builtin/` and identified by their * name. * - * @param PhabricatorUser Viewing user. - * @param list List of builtin file names. - * @return dict Dictionary of named builtins. + * @param PhabricatorUser Viewing user. + * @param list List of builtin file specs. + * @return dict Dictionary of named builtins. */ - public static function loadBuiltins(PhabricatorUser $user, array $names) { + public static function loadBuiltins(PhabricatorUser $user, array $builtins) { + $builtins = mpull($builtins, null, 'getBuiltinFileKey'); + $specs = array(); - foreach ($names as $name) { + foreach ($builtins as $key => $buitin) { $specs[] = array( 'originalPHID' => PhabricatorPHIDConstants::PHID_VOID, - 'transform' => 'builtin:'.$name, + 'transform' => $key, ); } @@ -981,41 +983,34 @@ final class PhabricatorFile extends PhabricatorFileDAO ->withTransforms($specs) ->execute(); - $files = mpull($files, null, 'getName'); - - $root = dirname(phutil_get_library_root('phabricator')); - $root = $root.'/resources/builtin/'; + $results = array(); + foreach ($files as $file) { + $builtin_key = $file->getBuiltinName(); + if ($builtin_key !== null) { + $results[$builtin_key] = $file; + } + } $build = array(); - foreach ($names as $name) { - if (isset($files[$name])) { + foreach ($builtins as $key => $builtin) { + if (isset($results[$key])) { continue; } - // This is just a sanity check to prevent loading arbitrary files. - if (basename($name) != $name) { - throw new Exception(pht("Invalid builtin name '%s'!", $name)); - } + $data = $builtin->loadBuiltinFileData(); - $path = $root.$name; - - if (!Filesystem::pathExists($path)) { - throw new Exception(pht("Builtin '%s' does not exist!", $path)); - } - - $data = Filesystem::readFile($path); $params = array( - 'name' => $name, + 'name' => $builtin->getBuiltinDisplayName(), 'ttl' => time() + (60 * 60 * 24 * 7), 'canCDN' => true, - 'builtin' => $name, + 'builtin' => $key, ); $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); $file = self::newFromFileData($data, $params); $xform = id(new PhabricatorTransformedFile()) ->setOriginalPHID(PhabricatorPHIDConstants::PHID_VOID) - ->setTransform('builtin:'.$name) + ->setTransform($key) ->setTransformedPHID($file->getPHID()) ->save(); unset($unguarded); @@ -1023,10 +1018,10 @@ final class PhabricatorFile extends PhabricatorFileDAO $file->attachObjectPHIDs(array()); $file->attachObjects(array()); - $files[$name] = $file; + $results[$key] = $file; } - return $files; + return $results; } @@ -1038,7 +1033,12 @@ final class PhabricatorFile extends PhabricatorFileDAO * @return PhabricatorFile Corresponding builtin file. */ public static function loadBuiltin(PhabricatorUser $user, $name) { - return idx(self::loadBuiltins($user, array($name)), $name); + $builtin = id(new PhabricatorFilesOnDiskBuiltinFile()) + ->setName($name); + + $key = $builtin->getBuiltinFileKey(); + + return idx(self::loadBuiltins($user, array($builtin)), $key); } public function getObjects() { @@ -1352,10 +1352,6 @@ final class PhabricatorFile extends PhabricatorFileDAO return true; } - public function shouldAllowSubscription($phid) { - return true; - } - /* -( PhabricatorTokenReceiverInterface )---------------------------------- */ diff --git a/src/applications/files/uploadsource/PhabricatorExecFutureFileUploadSource.php b/src/applications/files/uploadsource/PhabricatorExecFutureFileUploadSource.php new file mode 100644 index 0000000000..2e876c3e7a --- /dev/null +++ b/src/applications/files/uploadsource/PhabricatorExecFutureFileUploadSource.php @@ -0,0 +1,28 @@ +future = $future; + return $this; + } + + public function getExecFuture() { + return $this->future; + } + + protected function newDataIterator() { + $future = $this->getExecFuture(); + + return id(new LinesOfALargeExecFuture($future)) + ->setDelimiter(null); + } + + protected function getDataLength() { + return null; + } + +} diff --git a/src/applications/files/uploadsource/PhabricatorFileUploadSource.php b/src/applications/files/uploadsource/PhabricatorFileUploadSource.php new file mode 100644 index 0000000000..74b8e32389 --- /dev/null +++ b/src/applications/files/uploadsource/PhabricatorFileUploadSource.php @@ -0,0 +1,235 @@ +name = $name; + return $this; + } + + public function getName() { + return $this->name; + } + + public function setTTL($ttl) { + $this->ttl = $ttl; + return $this; + } + + public function getTTL() { + return $this->ttl; + } + + public function setViewPolicy($view_policy) { + $this->viewPolicy = $view_policy; + return $this; + } + + public function getViewPolicy() { + return $this->viewPolicy; + } + + public function uploadFile() { + if (!$this->shouldChunkFile()) { + return $this->writeSingleFile(); + } else { + return $this->writeChunkedFile(); + } + } + + private function getDataIterator() { + if (!$this->data) { + $this->data = $this->newDataIterator(); + } + return $this->data; + } + + private function getRope() { + if (!$this->rope) { + $this->rope = new PhutilRope(); + } + return $this->rope; + } + + abstract protected function newDataIterator(); + abstract protected function getDataLength(); + + private function readFileData() { + $data = $this->getDataIterator(); + + if (!$this->didRewind) { + $data->rewind(); + $this->didRewind = true; + } else { + $data->next(); + } + + if (!$data->valid()) { + return false; + } + + $rope = $this->getRope(); + $rope->append($data->current()); + + return true; + } + + private function shouldChunkFile() { + if ($this->shouldChunk !== null) { + return $this->shouldChunk; + } + + $threshold = PhabricatorFileStorageEngine::getChunkThreshold(); + + // If we don't know how large the file is, we're going to read some data + // from it until we know whether it's a small file or not. This will give + // us enough information to make a decision about chunking. + $length = $this->getDataLength(); + if ($length === null) { + $rope = $this->getRope(); + while ($this->readFileData()) { + $length = $rope->getByteLength(); + if ($length > $threshold) { + break; + } + } + } + + $this->shouldChunk = ($length > $threshold); + + return $this->shouldChunk; + } + + private function writeSingleFile() { + while ($this->readFileData()) { + // Read the entire file. + } + + $rope = $this->getRope(); + $data = $rope->getAsString(); + + $parameters = $this->getNewFileParameters(); + + return PhabricatorFile::newFromFileData($data, $parameters); + } + + private function writeChunkedFile() { + $engine = $this->getChunkEngine(); + + $parameters = $this->getNewFileParameters(); + + $parameters = array( + 'isPartial' => true, + ) + $parameters; + + $data_length = $this->getDataLength(); + if ($data_length !== null) { + $length = $data_length; + } else { + $length = 0; + } + + $file = PhabricatorFile::newChunkedFile($engine, $length, $parameters); + $file->save(); + + $rope = $this->getRope(); + + // Read the source, writing chunks as we get enough data. + while ($this->readFileData()) { + while (true) { + $rope_length = $rope->getByteLength(); + if ($rope_length < $engine->getChunkSize()) { + break; + } + $this->writeChunk($file, $engine); + } + } + + // If we have extra bytes at the end, write them. + if ($rope->getByteLength()) { + $this->writeChunk($file, $engine); + } + + $file->setIsPartial(0); + if ($data_length === null) { + $file->setByteSize($this->getTotalBytesWritten()); + } + $file->save(); + + return $file; + } + + private function writeChunk( + PhabricatorFile $file, + PhabricatorFileStorageEngine $engine) { + + $offset = $this->getTotalBytesWritten(); + $max_length = $engine->getChunkSize(); + $rope = $this->getRope(); + + $data = $rope->getPrefixBytes($max_length); + $actual_length = strlen($data); + $rope->removeBytesFromHead($actual_length); + + $chunk_data = PhabricatorFile::newFromFileData( + $data, + array( + 'name' => $file->getMonogram().'.chunk-'.$offset, + 'viewPolicy' => PhabricatorPolicies::POLICY_NOONE, + )); + + $chunk = PhabricatorFileChunk::initializeNewChunk( + $file->getStorageHandle(), + $offset, + $offset + $actual_length); + + $chunk + ->setDataFilePHID($chunk_data->getPHID()) + ->save(); + + $this->setTotalBytesWritten($offset + $actual_length); + + return $chunk; + } + + private function getNewFileParameters() { + return array( + 'name' => $this->getName(), + 'ttl' => $this->getTTL(), + 'viewPolicy' => $this->getViewPolicy(), + ); + } + + private function getChunkEngine() { + $chunk_engines = PhabricatorFileStorageEngine::loadWritableChunkEngines(); + if (!$chunk_engines) { + throw new Exception( + pht( + 'Unable to upload file: this server is not configured with any '. + 'storage engine which can store large files.')); + } + + return head($chunk_engines); + } + + private function setTotalBytesWritten($total_bytes_written) { + $this->totalBytesWritten = $total_bytes_written; + return $this; + } + + private function getTotalBytesWritten() { + return $this->totalBytesWritten; + } + +} diff --git a/src/applications/fund/storage/FundInitiative.php b/src/applications/fund/storage/FundInitiative.php index 57e86beccf..3375551443 100644 --- a/src/applications/fund/storage/FundInitiative.php +++ b/src/applications/fund/storage/FundInitiative.php @@ -182,10 +182,6 @@ final class FundInitiative extends FundDAO return true; } - public function shouldAllowSubscription($phid) { - return true; - } - /* -( PhabricatorTokenRecevierInterface )---------------------------------- */ diff --git a/src/applications/harbormaster/storage/build/HarbormasterBuildArtifact.php b/src/applications/harbormaster/storage/build/HarbormasterBuildArtifact.php index 0b195db88f..bb5f8382ba 100644 --- a/src/applications/harbormaster/storage/build/HarbormasterBuildArtifact.php +++ b/src/applications/harbormaster/storage/build/HarbormasterBuildArtifact.php @@ -38,6 +38,9 @@ final class HarbormasterBuildArtifact extends HarbormasterDAO 'key_garbagecollect' => array( 'columns' => array('artifactType', 'dateCreated'), ), + 'key_target' => array( + 'columns' => array('buildTargetPHID', 'artifactType'), + ), ), ) + parent::getConfiguration(); } diff --git a/src/applications/harbormaster/storage/configuration/HarbormasterBuildPlan.php b/src/applications/harbormaster/storage/configuration/HarbormasterBuildPlan.php index 11cb6260b7..5ac9696813 100644 --- a/src/applications/harbormaster/storage/configuration/HarbormasterBuildPlan.php +++ b/src/applications/harbormaster/storage/configuration/HarbormasterBuildPlan.php @@ -129,10 +129,6 @@ final class HarbormasterBuildPlan extends HarbormasterDAO return true; } - public function shouldAllowSubscription($phid) { - return true; - } - /* -( PhabricatorApplicationTransactionInterface )------------------------- */ diff --git a/src/applications/herald/storage/HeraldRule.php b/src/applications/herald/storage/HeraldRule.php index 51707fcc8a..8d585263c0 100644 --- a/src/applications/herald/storage/HeraldRule.php +++ b/src/applications/herald/storage/HeraldRule.php @@ -332,10 +332,6 @@ final class HeraldRule extends HeraldDAO return true; } - public function shouldAllowSubscription($phid) { - return true; - } - /* -( PhabricatorDestructibleInterface )----------------------------------- */ diff --git a/src/applications/legalpad/storage/LegalpadDocument.php b/src/applications/legalpad/storage/LegalpadDocument.php index 4c6e04a26a..51f158a978 100644 --- a/src/applications/legalpad/storage/LegalpadDocument.php +++ b/src/applications/legalpad/storage/LegalpadDocument.php @@ -167,10 +167,6 @@ final class LegalpadDocument extends LegalpadDAO return true; } - public function shouldAllowSubscription($phid) { - return true; - } - /* -( PhabricatorPolicyInterface )----------------------------------------- */ diff --git a/src/applications/macro/storage/PhabricatorFileImageMacro.php b/src/applications/macro/storage/PhabricatorFileImageMacro.php index 72a6577924..5cf23133a3 100644 --- a/src/applications/macro/storage/PhabricatorFileImageMacro.php +++ b/src/applications/macro/storage/PhabricatorFileImageMacro.php @@ -115,10 +115,6 @@ final class PhabricatorFileImageMacro extends PhabricatorFileDAO return true; } - public function shouldAllowSubscription($phid) { - return true; - } - /* -( PhabricatorTokenRecevierInterface )---------------------------------- */ diff --git a/src/applications/maniphest/storage/ManiphestTask.php b/src/applications/maniphest/storage/ManiphestTask.php index 9f8dad1cd8..cc9a5bd80a 100644 --- a/src/applications/maniphest/storage/ManiphestTask.php +++ b/src/applications/maniphest/storage/ManiphestTask.php @@ -227,10 +227,6 @@ final class ManiphestTask extends ManiphestDAO return true; } - public function shouldAllowSubscription($phid) { - return true; - } - /* -( Markup Interface )--------------------------------------------------- */ diff --git a/src/applications/metamta/query/PhabricatorMetaMTAMemberQuery.php b/src/applications/metamta/query/PhabricatorMetaMTAMemberQuery.php index f565baf595..e06da5f4e3 100644 --- a/src/applications/metamta/query/PhabricatorMetaMTAMemberQuery.php +++ b/src/applications/metamta/query/PhabricatorMetaMTAMemberQuery.php @@ -42,20 +42,48 @@ final class PhabricatorMetaMTAMemberQuery extends PhabricatorQuery { $projects = id(new PhabricatorProjectQuery()) ->setViewer($this->getViewer()) ->withPHIDs($phids) + ->needMembers(true) + ->needWatchers(true) ->execute(); - $subscribers = id(new PhabricatorSubscribersQuery()) - ->withObjectPHIDs($phids) - ->execute(); + $edge_type = PhabricatorProjectSilencedEdgeType::EDGECONST; + + $edge_query = id(new PhabricatorEdgeQuery()) + ->withSourcePHIDs($phids) + ->withEdgeTypes( + array( + $edge_type, + )); + + $edge_query->execute(); $projects = mpull($projects, null, 'getPHID'); foreach ($phids as $phid) { $project = idx($projects, $phid); + if (!$project) { $results[$phid] = array(); - } else { - $results[$phid] = idx($subscribers, $phid, array()); + continue; } + + // Recipients are members who haven't silenced the project, plus + // watchers. + + $members = $project->getMemberPHIDs(); + $members = array_fuse($members); + + $watchers = $project->getWatcherPHIDs(); + $watchers = array_fuse($watchers); + + $silenced = $edge_query->getDestinationPHIDs( + array($phid), + array($edge_type)); + $silenced = array_fuse($silenced); + + $result_map = array_diff_key($members, $silenced); + $result_map = $result_map + $watchers; + + $results[$phid] = array_values($result_map); } break; default: diff --git a/src/applications/passphrase/storage/PassphraseCredential.php b/src/applications/passphrase/storage/PassphraseCredential.php index 4d705aff83..f263523b49 100644 --- a/src/applications/passphrase/storage/PassphraseCredential.php +++ b/src/applications/passphrase/storage/PassphraseCredential.php @@ -161,10 +161,6 @@ final class PassphraseCredential extends PassphraseDAO return true; } - public function shouldAllowSubscription($phid) { - return true; - } - /* -( PhabricatorDestructibleInterface )----------------------------------- */ diff --git a/src/applications/paste/storage/PhabricatorPaste.php b/src/applications/paste/storage/PhabricatorPaste.php index 022b998bac..624c70c410 100644 --- a/src/applications/paste/storage/PhabricatorPaste.php +++ b/src/applications/paste/storage/PhabricatorPaste.php @@ -159,10 +159,6 @@ final class PhabricatorPaste extends PhabricatorPasteDAO return true; } - public function shouldAllowSubscription($phid) { - return true; - } - /* -( PhabricatorTokenReceiverInterface )---------------------------------- */ diff --git a/src/applications/people/application/PhabricatorPeopleApplication.php b/src/applications/people/application/PhabricatorPeopleApplication.php index 45599907c8..48598ba838 100644 --- a/src/applications/people/application/PhabricatorPeopleApplication.php +++ b/src/applications/people/application/PhabricatorPeopleApplication.php @@ -63,10 +63,12 @@ final class PhabricatorPeopleApplication extends PhabricatorApplication { 'picture/(?P[1-9]\d*)/' => 'PhabricatorPeopleProfilePictureController', ), - '/p/(?P[\w._-]+)/' - => 'PhabricatorPeopleProfileController', - '/p/(?P[\w._-]+)/calendar/' - => 'PhabricatorPeopleCalendarController', + '/p/(?P[\w._-]+)/' => array( + '' => 'PhabricatorPeopleProfileViewController', + 'panel/' + => $this->getPanelRouting('PhabricatorPeopleProfilePanelController'), + 'calendar/' => 'PhabricatorPeopleCalendarController', + ), ); } diff --git a/src/applications/people/controller/PhabricatorPeopleCalendarController.php b/src/applications/people/controller/PhabricatorPeopleCalendarController.php index a5e64199c5..ed3d557fb8 100644 --- a/src/applications/people/controller/PhabricatorPeopleCalendarController.php +++ b/src/applications/people/controller/PhabricatorPeopleCalendarController.php @@ -1,34 +1,27 @@ getViewer(); + $username = $request->getURIData('username'); - public function willProcessRequest(array $data) { - $this->username = idx($data, 'username'); - } - - public function processRequest() { - $viewer = $this->getRequest()->getUser(); $user = id(new PhabricatorPeopleQuery()) ->setViewer($viewer) - ->withUsernames(array($this->username)) + ->withUsernames(array($username)) ->needProfileImage(true) ->executeOne(); - if (!$user) { return new Aphront404Response(); } + $this->setUser($user); + $picture = $user->getProfileImageURI(); $now = time(); @@ -89,16 +82,16 @@ final class PhabricatorPeopleCalendarController $month_view->addEvent($event); } - $name = $user->getUsername(); + $nav = $this->getProfileMenu(); + $nav->selectFilter('calendar'); - $nav = $this->buildIconNavView($user); - $nav->selectFilter("{$name}/calendar/"); - $nav->appendChild($month_view); + $crumbs = $this->buildApplicationCrumbs(); + $crumbs->addTextCrumb(pht('Calendar')); - return $this->buildApplicationPage( - $nav, - array( - 'title' => pht('Calendar'), - )); + return $this->newPage() + ->setTitle(pht('Calendar')) + ->setNavigation($nav) + ->setCrumbs($crumbs) + ->appendChild($month_view); } } diff --git a/src/applications/people/controller/PhabricatorPeopleController.php b/src/applications/people/controller/PhabricatorPeopleController.php index b293c0f72c..e3b60eff2b 100644 --- a/src/applications/people/controller/PhabricatorPeopleController.php +++ b/src/applications/people/controller/PhabricatorPeopleController.php @@ -44,49 +44,4 @@ abstract class PhabricatorPeopleController extends PhabricatorController { return $this->buildSideNavView(true)->getMenu(); } - public function buildIconNavView(PhabricatorUser $user) { - $viewer = $this->getViewer(); - $picture = $user->getProfileImageURI(); - $name = $user->getUsername(); - - $nav = new AphrontSideNavFilterView(); - $nav->setIconNav(true); - $nav->setBaseURI(new PhutilURI('/p/')); - $nav->addIcon("{$name}/", $name, null, $picture); - - $class = 'PhabricatorCalendarApplication'; - if (PhabricatorApplication::isClassInstalledForViewer($class, $viewer)) { - $nav->addIcon( - "{$name}/calendar/", pht('Calendar'), 'fa-calendar'); - } - - $class = 'PhabricatorManiphestApplication'; - if (PhabricatorApplication::isClassInstalledForViewer($class, $viewer)) { - $phid = $user->getPHID(); - $view_uri = sprintf( - '/maniphest/?statuses=open()&assigned=%s#R', - $phid); - $nav->addIcon( - 'maniphest', pht('Open Tasks'), 'fa-anchor', null, $view_uri); - } - - $class = 'PhabricatorDifferentialApplication'; - if (PhabricatorApplication::isClassInstalledForViewer($class, $viewer)) { - $username = phutil_escape_uri($name); - $view_uri = '/differential/?authors='.$username; - $nav->addIcon( - 'differential', pht('Revisions'), 'fa-cog', null, $view_uri); - } - - $class = 'PhabricatorAuditApplication'; - if (PhabricatorApplication::isClassInstalledForViewer($class, $viewer)) { - $username = phutil_escape_uri($name); - $view_uri = '/audit/?authors='.$username; - $nav->addIcon( - 'audit', pht('Commits'), 'fa-code', null, $view_uri); - } - - return $nav; - } - } diff --git a/src/applications/people/controller/PhabricatorPeopleProfileController.php b/src/applications/people/controller/PhabricatorPeopleProfileController.php index a4378f380c..74705f9809 100644 --- a/src/applications/people/controller/PhabricatorPeopleProfileController.php +++ b/src/applications/people/controller/PhabricatorPeopleProfileController.php @@ -1,257 +1,63 @@ username = idx($data, 'username'); + public function setUser(PhabricatorUser $user) { + $this->user = $user; + return $this; } - public function processRequest() { - $viewer = $this->getRequest()->getUser(); - - $user = id(new PhabricatorPeopleQuery()) - ->setViewer($viewer) - ->withUsernames(array($this->username)) - ->needBadges(true) - ->needProfileImage(true) - ->needAvailability(true) - ->executeOne(); - if (!$user) { - return new Aphront404Response(); - } - - $profile = $user->loadUserProfile(); - $username = phutil_escape_uri($user->getUserName()); - - $picture = $user->getProfileImageURI(); - - $header = id(new PHUIHeaderView()) - ->setHeader($user->getFullName()) - ->setSubheader($profile->getTitle()) - ->setImage($picture); - - $actions = id(new PhabricatorActionListView()) - ->setObject($user) - ->setUser($viewer); - - $can_edit = PhabricatorPolicyFilter::hasCapability( - $viewer, - $user, - PhabricatorPolicyCapability::CAN_EDIT); - - $actions->addAction( - id(new PhabricatorActionView()) - ->setIcon('fa-pencil') - ->setName(pht('Edit Profile')) - ->setHref($this->getApplicationURI('editprofile/'.$user->getID().'/')) - ->setDisabled(!$can_edit) - ->setWorkflow(!$can_edit)); - - $actions->addAction( - id(new PhabricatorActionView()) - ->setIcon('fa-picture-o') - ->setName(pht('Edit Profile Picture')) - ->setHref($this->getApplicationURI('picture/'.$user->getID().'/')) - ->setDisabled(!$can_edit) - ->setWorkflow(!$can_edit)); - - $class = 'PhabricatorConpherenceApplication'; - if (PhabricatorApplication::isClassInstalledForViewer($class, $viewer)) { - $href = id(new PhutilURI('/conpherence/new/')) - ->setQueryParam('participant', $user->getPHID()); - - $can_send = $viewer->isLoggedIn(); - - $actions->addAction( - id(new PhabricatorActionView()) - ->setIcon('fa-comments') - ->setName(pht('Send Message')) - ->setWorkflow(true) - ->setDisabled(!$can_send) - ->setHref($href)); - } - - if ($viewer->getIsAdmin()) { - $actions->addAction( - id(new PhabricatorActionView()) - ->setIcon('fa-wrench') - ->setName(pht('Edit Settings')) - ->setDisabled(!$can_edit) - ->setWorkflow(!$can_edit) - ->setHref('/settings/'.$user->getID().'/')); - - if ($user->getIsAdmin()) { - $empower_icon = 'fa-arrow-circle-o-down'; - $empower_name = pht('Remove Administrator'); - } else { - $empower_icon = 'fa-arrow-circle-o-up'; - $empower_name = pht('Make Administrator'); - } - - $actions->addAction( - id(new PhabricatorActionView()) - ->setIcon($empower_icon) - ->setName($empower_name) - ->setDisabled(($user->getPHID() == $viewer->getPHID())) - ->setWorkflow(true) - ->setHref($this->getApplicationURI('empower/'.$user->getID().'/'))); - - $actions->addAction( - id(new PhabricatorActionView()) - ->setIcon('fa-tag') - ->setName(pht('Change Username')) - ->setWorkflow(true) - ->setHref($this->getApplicationURI('rename/'.$user->getID().'/'))); - - if ($user->getIsDisabled()) { - $disable_icon = 'fa-check-circle-o'; - $disable_name = pht('Enable User'); - } else { - $disable_icon = 'fa-ban'; - $disable_name = pht('Disable User'); - } - - $actions->addAction( - id(new PhabricatorActionView()) - ->setIcon($disable_icon) - ->setName($disable_name) - ->setDisabled(($user->getPHID() == $viewer->getPHID())) - ->setWorkflow(true) - ->setHref($this->getApplicationURI('disable/'.$user->getID().'/'))); - - $actions->addAction( - id(new PhabricatorActionView()) - ->setIcon('fa-times') - ->setName(pht('Delete User')) - ->setDisabled(($user->getPHID() == $viewer->getPHID())) - ->setWorkflow(true) - ->setHref($this->getApplicationURI('delete/'.$user->getID().'/'))); - - $can_welcome = $user->canEstablishWebSessions(); - - $actions->addAction( - id(new PhabricatorActionView()) - ->setIcon('fa-envelope') - ->setName(pht('Send Welcome Email')) - ->setWorkflow(true) - ->setDisabled(!$can_welcome) - ->setHref($this->getApplicationURI('welcome/'.$user->getID().'/'))); - } - - $properties = $this->buildPropertyView($user, $actions); - $name = $user->getUsername(); - - $crumbs = $this->buildApplicationCrumbs(); - $crumbs->addTextCrumb($name); - - $object_box = id(new PHUIObjectBoxView()) - ->setHeader($header) - ->addPropertyList($properties); - - $feed = id(new PHUIObjectBoxView()) - ->setHeaderText(pht('Recent Activity')) - ->appendChild($this->buildPeopleFeed($user, $viewer)); - - $badges = $this->buildBadgesView($user); - - $nav = $this->buildIconNavView($user); - $nav->selectFilter("{$name}/"); - $nav->appendChild($object_box); - $nav->appendChild($badges); - $nav->appendChild($feed); - - return $this->buildApplicationPage( - $nav, - array( - 'title' => $user->getUsername(), - )); + public function getUser() { + return $this->user; } - private function buildPropertyView( - PhabricatorUser $user, - PhabricatorActionListView $actions) { + public function buildApplicationMenu() { + $menu = $this->newApplicationMenu(); - $viewer = $this->getRequest()->getUser(); - $view = id(new PHUIPropertyListView()) - ->setUser($viewer) - ->setObject($user) - ->setActionList($actions); + $profile_menu = $this->getProfileMenu(); + if ($profile_menu) { + $menu->setProfileMenu($profile_menu); + } - $field_list = PhabricatorCustomField::getObjectFields( - $user, - PhabricatorCustomField::ROLE_VIEW); - $field_list->appendFieldsToPropertyList($user, $viewer, $view); - - return $view; + return $menu; } - private function buildBadgesView( - PhabricatorUser $user) { + protected function getProfileMenu() { + if (!$this->profileMenu) { + $user = $this->getUser(); + if ($user) { + $viewer = $this->getViewer(); - $viewer = $this->getViewer(); - $class = 'PhabricatorBadgesApplication'; - $box = null; - - if (PhabricatorApplication::isClassInstalledForViewer($class, $viewer)) { - $badge_phids = $user->getBadgePHIDs(); - if ($badge_phids) { - $badges = id(new PhabricatorBadgesQuery()) + $engine = id(new PhabricatorPeopleProfilePanelEngine()) ->setViewer($viewer) - ->withPHIDs($badge_phids) - ->withStatuses(array(PhabricatorBadgesBadge::STATUS_ACTIVE)) - ->execute(); + ->setProfileObject($user); - $flex = new PHUIBadgeBoxView(); - foreach ($badges as $badge) { - $item = id(new PHUIBadgeView()) - ->setIcon($badge->getIcon()) - ->setHeader($badge->getName()) - ->setSubhead($badge->getFlavor()) - ->setQuality($badge->getQuality()); - $flex->addItem($item); - } - - $box = id(new PHUIObjectBoxView()) - ->setHeaderText(pht('Badges')) - ->appendChild($flex); - } + $this->profileMenu = $engine->buildNavigation(); } - return $box; + } + + return $this->profileMenu; } - private function buildPeopleFeed( - PhabricatorUser $user, - $viewer) { + protected function buildApplicationCrumbs() { + $crumbs = parent::buildApplicationCrumbs(); - $query = new PhabricatorFeedQuery(); - $query->setFilterPHIDs( - array( - $user->getPHID(), - )); - $query->setLimit(100); - $query->setViewer($viewer); - $stories = $query->execute(); - - $builder = new PhabricatorFeedBuilder($stories); - $builder->setUser($viewer); - $builder->setShowHovercards(true); - $builder->setNoDataString(pht('To begin on such a grand journey, '. - 'requires but just a single step.')); - $view = $builder->buildView(); - - return phutil_tag_div('phabricator-project-feed', $view->render()); + $user = $this->getUser(); + if ($user) { + $crumbs->addTextCrumb( + $user->getUsername(), + urisprintf('/p/%s/', $user->getUsername())); + } + return $crumbs; } } diff --git a/src/applications/people/controller/PhabricatorPeopleProfileEditController.php b/src/applications/people/controller/PhabricatorPeopleProfileEditController.php index f53278b536..b438093be7 100644 --- a/src/applications/people/controller/PhabricatorPeopleProfileEditController.php +++ b/src/applications/people/controller/PhabricatorPeopleProfileEditController.php @@ -1,25 +1,15 @@ id = $data['id']; - } - - public function processRequest() { - $request = $this->getRequest(); - $viewer = $request->getUser(); + public function handleRequest(AphrontRequest $request) { + $viewer = $this->getViewer(); + $id = $request->getURIData('id'); $user = id(new PhabricatorPeopleQuery()) ->setViewer($viewer) - ->withIDs(array($this->id)) + ->withIDs(array($id)) ->needProfileImage(true) ->requireCapabilities( array( @@ -31,6 +21,8 @@ final class PhabricatorPeopleProfileEditController return new Aphront404Response(); } + $this->setUser($user); + $profile_uri = '/p/'.$user->getUsername().'/'; $field_list = PhabricatorCustomField::getObjectFields( @@ -91,14 +83,12 @@ final class PhabricatorPeopleProfileEditController $form_box->setInfoView($note); } - $nav = $this->buildIconNavView($user); - $nav->selectFilter('/'); - $nav->appendChild($form_box); + $crumbs = $this->buildApplicationCrumbs(); + $crumbs->addTextCrumb(pht('Edit Profile')); - return $this->buildApplicationPage( - $nav, - array( - 'title' => $title, - )); + return $this->newPage() + ->setTitle($title) + ->setCrumbs($crumbs) + ->appendChild($form_box); } } diff --git a/src/applications/people/controller/PhabricatorPeopleProfilePictureController.php b/src/applications/people/controller/PhabricatorPeopleProfilePictureController.php index 9dabd50f66..0d9554e264 100644 --- a/src/applications/people/controller/PhabricatorPeopleProfilePictureController.php +++ b/src/applications/people/controller/PhabricatorPeopleProfilePictureController.php @@ -1,25 +1,15 @@ id = $data['id']; - } - - public function processRequest() { - $request = $this->getRequest(); - $viewer = $request->getUser(); + public function handleRequest(AphrontRequest $request) { + $viewer = $this->getViewer(); + $id = $request->getURIData('id'); $user = id(new PhabricatorPeopleQuery()) ->setViewer($viewer) - ->withIDs(array($this->id)) + ->withIDs(array($id)) ->needProfileImage(true) ->requireCapabilities( array( @@ -31,6 +21,8 @@ final class PhabricatorPeopleProfilePictureController return new Aphront404Response(); } + $this->setUser($user); + $profile_uri = '/p/'.$user->getUsername().'/'; $supported_formats = PhabricatorFile::getTransformableImageFormats(); @@ -256,15 +248,16 @@ final class PhabricatorPeopleProfilePictureController ->setHeaderText(pht('Upload New Picture')) ->setForm($upload_form); - $nav = $this->buildIconNavView($user); - $nav->selectFilter('/'); - $nav->appendChild($form_box); - $nav->appendChild($upload_box); + $crumbs = $this->buildApplicationCrumbs(); + $crumbs->addTextCrumb(pht('Edit Profile Picture')); - return $this->buildApplicationPage( - $nav, - array( - 'title' => $title, - )); + return $this->newPage() + ->setTitle($title) + ->setCrumbs($crumbs) + ->appendChild( + array( + $form_box, + $upload_box, + )); } } diff --git a/src/applications/people/controller/PhabricatorPeopleProfileViewController.php b/src/applications/people/controller/PhabricatorPeopleProfileViewController.php new file mode 100644 index 0000000000..a515dda959 --- /dev/null +++ b/src/applications/people/controller/PhabricatorPeopleProfileViewController.php @@ -0,0 +1,252 @@ +getViewer(); + $username = $request->getURIData('username'); + + $user = id(new PhabricatorPeopleQuery()) + ->setViewer($viewer) + ->withUsernames(array($username)) + ->needBadges(true) + ->needProfileImage(true) + ->needAvailability(true) + ->executeOne(); + if (!$user) { + return new Aphront404Response(); + } + + $this->setUser($user); + + $profile = $user->loadUserProfile(); + $picture = $user->getProfileImageURI(); + + $header = id(new PHUIHeaderView()) + ->setHeader($user->getFullName()) + ->setSubheader($profile->getTitle()) + ->setImage($picture); + + $actions = id(new PhabricatorActionListView()) + ->setObject($user) + ->setUser($viewer); + + $can_edit = PhabricatorPolicyFilter::hasCapability( + $viewer, + $user, + PhabricatorPolicyCapability::CAN_EDIT); + + $actions->addAction( + id(new PhabricatorActionView()) + ->setIcon('fa-pencil') + ->setName(pht('Edit Profile')) + ->setHref($this->getApplicationURI('editprofile/'.$user->getID().'/')) + ->setDisabled(!$can_edit) + ->setWorkflow(!$can_edit)); + + $actions->addAction( + id(new PhabricatorActionView()) + ->setIcon('fa-picture-o') + ->setName(pht('Edit Profile Picture')) + ->setHref($this->getApplicationURI('picture/'.$user->getID().'/')) + ->setDisabled(!$can_edit) + ->setWorkflow(!$can_edit)); + + $class = 'PhabricatorConpherenceApplication'; + if (PhabricatorApplication::isClassInstalledForViewer($class, $viewer)) { + $href = id(new PhutilURI('/conpherence/new/')) + ->setQueryParam('participant', $user->getPHID()); + + $can_send = $viewer->isLoggedIn(); + + $actions->addAction( + id(new PhabricatorActionView()) + ->setIcon('fa-comments') + ->setName(pht('Send Message')) + ->setWorkflow(true) + ->setDisabled(!$can_send) + ->setHref($href)); + } + + if ($viewer->getIsAdmin()) { + $actions->addAction( + id(new PhabricatorActionView()) + ->setIcon('fa-wrench') + ->setName(pht('Edit Settings')) + ->setDisabled(!$can_edit) + ->setWorkflow(!$can_edit) + ->setHref('/settings/'.$user->getID().'/')); + + if ($user->getIsAdmin()) { + $empower_icon = 'fa-arrow-circle-o-down'; + $empower_name = pht('Remove Administrator'); + } else { + $empower_icon = 'fa-arrow-circle-o-up'; + $empower_name = pht('Make Administrator'); + } + + $actions->addAction( + id(new PhabricatorActionView()) + ->setIcon($empower_icon) + ->setName($empower_name) + ->setDisabled(($user->getPHID() == $viewer->getPHID())) + ->setWorkflow(true) + ->setHref($this->getApplicationURI('empower/'.$user->getID().'/'))); + + $actions->addAction( + id(new PhabricatorActionView()) + ->setIcon('fa-tag') + ->setName(pht('Change Username')) + ->setWorkflow(true) + ->setHref($this->getApplicationURI('rename/'.$user->getID().'/'))); + + if ($user->getIsDisabled()) { + $disable_icon = 'fa-check-circle-o'; + $disable_name = pht('Enable User'); + } else { + $disable_icon = 'fa-ban'; + $disable_name = pht('Disable User'); + } + + $actions->addAction( + id(new PhabricatorActionView()) + ->setIcon($disable_icon) + ->setName($disable_name) + ->setDisabled(($user->getPHID() == $viewer->getPHID())) + ->setWorkflow(true) + ->setHref($this->getApplicationURI('disable/'.$user->getID().'/'))); + + $actions->addAction( + id(new PhabricatorActionView()) + ->setIcon('fa-times') + ->setName(pht('Delete User')) + ->setDisabled(($user->getPHID() == $viewer->getPHID())) + ->setWorkflow(true) + ->setHref($this->getApplicationURI('delete/'.$user->getID().'/'))); + + $can_welcome = $user->canEstablishWebSessions(); + + $actions->addAction( + id(new PhabricatorActionView()) + ->setIcon('fa-envelope') + ->setName(pht('Send Welcome Email')) + ->setWorkflow(true) + ->setDisabled(!$can_welcome) + ->setHref($this->getApplicationURI('welcome/'.$user->getID().'/'))); + } + + $properties = $this->buildPropertyView($user, $actions); + $name = $user->getUsername(); + + $crumbs = $this->buildApplicationCrumbs(); + $crumbs->addTextCrumb($name); + + $object_box = id(new PHUIObjectBoxView()) + ->setHeader($header) + ->addPropertyList($properties); + + $feed = id(new PHUIObjectBoxView()) + ->setHeaderText(pht('Recent Activity')) + ->appendChild($this->buildPeopleFeed($user, $viewer)); + + $badges = $this->buildBadgesView($user); + + $nav = $this->getProfileMenu(); + $nav->selectFilter(PhabricatorPeopleProfilePanelEngine::PANEL_PROFILE); + + $crumbs = $this->buildApplicationCrumbs(); + + return $this->newPage() + ->setTitle($user->getUsername()) + ->setNavigation($nav) + ->setCrumbs($crumbs) + ->appendChild( + array( + $object_box, + $badges, + $feed, + )); + } + + private function buildPropertyView( + PhabricatorUser $user, + PhabricatorActionListView $actions) { + + $viewer = $this->getRequest()->getUser(); + $view = id(new PHUIPropertyListView()) + ->setUser($viewer) + ->setObject($user) + ->setActionList($actions); + + $field_list = PhabricatorCustomField::getObjectFields( + $user, + PhabricatorCustomField::ROLE_VIEW); + $field_list->appendFieldsToPropertyList($user, $viewer, $view); + + return $view; + } + + private function buildBadgesView( + PhabricatorUser $user) { + + $viewer = $this->getViewer(); + $class = 'PhabricatorBadgesApplication'; + $box = null; + + if (PhabricatorApplication::isClassInstalledForViewer($class, $viewer)) { + $badge_phids = $user->getBadgePHIDs(); + if ($badge_phids) { + $badges = id(new PhabricatorBadgesQuery()) + ->setViewer($viewer) + ->withPHIDs($badge_phids) + ->withStatuses(array(PhabricatorBadgesBadge::STATUS_ACTIVE)) + ->execute(); + + $flex = new PHUIBadgeBoxView(); + foreach ($badges as $badge) { + $item = id(new PHUIBadgeView()) + ->setIcon($badge->getIcon()) + ->setHeader($badge->getName()) + ->setSubhead($badge->getFlavor()) + ->setQuality($badge->getQuality()); + $flex->addItem($item); + } + + $box = id(new PHUIObjectBoxView()) + ->setHeaderText(pht('Badges')) + ->appendChild($flex); + } + } + return $box; + } + + private function buildPeopleFeed( + PhabricatorUser $user, + $viewer) { + + $query = new PhabricatorFeedQuery(); + $query->setFilterPHIDs( + array( + $user->getPHID(), + )); + $query->setLimit(100); + $query->setViewer($viewer); + $stories = $query->execute(); + + $builder = new PhabricatorFeedBuilder($stories); + $builder->setUser($viewer); + $builder->setShowHovercards(true); + $builder->setNoDataString(pht('To begin on such a grand journey, '. + 'requires but just a single step.')); + $view = $builder->buildView(); + + return phutil_tag_div('phabricator-project-feed', $view->render()); + + } + +} diff --git a/src/applications/people/engine/PhabricatorPeopleProfilePanelEngine.php b/src/applications/people/engine/PhabricatorPeopleProfilePanelEngine.php new file mode 100644 index 0000000000..60b11ffebb --- /dev/null +++ b/src/applications/people/engine/PhabricatorPeopleProfilePanelEngine.php @@ -0,0 +1,96 @@ +getProfileObject(); + $username = $user->getUsername(); + $username = phutil_escape_uri($username); + return "/p/{$username}/panel/{$path}"; + } + + protected function getBuiltinProfilePanels($object) { + $viewer = $this->getViewer(); + + $panels = array(); + + $panels[] = $this->newPanel() + ->setBuiltinKey(self::PANEL_PROFILE) + ->setPanelKey(PhabricatorPeopleDetailsProfilePanel::PANELKEY); + + // TODO: Convert this into a proper panel type. + $have_calendar = PhabricatorApplication::isClassInstalledForViewer( + 'PhabricatorCalendarApplication', + $viewer); + if ($have_calendar) { + $uri = urisprintf( + '/p/%s/calendar/', + $object->getUsername()); + + $panels[] = $this->newPanel() + ->setBuiltinKey('calendar') + ->setPanelKey(PhabricatorLinkProfilePanel::PANELKEY) + ->setPanelProperty('icon', 'calendar') + ->setPanelProperty('name', pht('Calendar')) + ->setPanelProperty('uri', $uri); + } + + $have_maniphest = PhabricatorApplication::isClassInstalledForViewer( + 'PhabricatorManiphestApplication', + $viewer); + if ($have_maniphest) { + $uri = urisprintf( + '/maniphest/?statuses=open()&assigned=%s#R', + $object->getPHID()); + + $panels[] = $this->newPanel() + ->setBuiltinKey('tasks') + ->setPanelKey(PhabricatorLinkProfilePanel::PANELKEY) + ->setPanelProperty('icon', 'maniphest') + ->setPanelProperty('name', pht('Open Tasks')) + ->setPanelProperty('uri', $uri); + } + + $have_differential = PhabricatorApplication::isClassInstalledForViewer( + 'PhabricatorDifferentialApplication', + $viewer); + if ($have_differential) { + $uri = urisprintf( + '/differential/?authors=%s#R', + $object->getPHID()); + + $panels[] = $this->newPanel() + ->setBuiltinKey('revisions') + ->setPanelKey(PhabricatorLinkProfilePanel::PANELKEY) + ->setPanelProperty('icon', 'differential') + ->setPanelProperty('name', pht('Revisions')) + ->setPanelProperty('uri', $uri); + } + + $have_diffusion = PhabricatorApplication::isClassInstalledForViewer( + 'PhabricatorDiffusionApplication', + $viewer); + if ($have_diffusion) { + $uri = urisprintf( + '/audit/?authors=%s#R', + $object->getPHID()); + + $panels[] = $this->newPanel() + ->setBuiltinKey('commits') + ->setPanelKey(PhabricatorLinkProfilePanel::PANELKEY) + ->setPanelProperty('icon', 'diffusion') + ->setPanelProperty('name', pht('Commits')) + ->setPanelProperty('uri', $uri); + } + + return $panels; + } + +} diff --git a/src/applications/people/profilepanel/PhabricatorPeopleDetailsProfilePanel.php b/src/applications/people/profilepanel/PhabricatorPeopleDetailsProfilePanel.php new file mode 100644 index 0000000000..83d45dfb9d --- /dev/null +++ b/src/applications/people/profilepanel/PhabricatorPeopleDetailsProfilePanel.php @@ -0,0 +1,59 @@ +getPanelProperty('name'); + + if (strlen($name)) { + return $name; + } + + return $this->getDefaultName(); + } + + public function buildEditEngineFields( + PhabricatorProfilePanelConfiguration $config) { + return array( + id(new PhabricatorTextEditField()) + ->setKey('name') + ->setLabel(pht('Name')) + ->setPlaceholder($this->getDefaultName()) + ->setValue($config->getPanelProperty('name')), + ); + } + + protected function newNavigationMenuItems( + PhabricatorProfilePanelConfiguration $config) { + + $user = $config->getProfileObject(); + + $picture = $user->getProfileImageURI(); + $name = $user->getUsername(); + $href = urisprintf( + '/p/%s/', + $user->getUsername()); + + $item = $this->newItem() + ->setHref($href) + ->setName($name) + ->setProfileImage($picture); + + return array( + $item, + ); + } + +} diff --git a/src/applications/people/typeahead/PhabricatorPeopleDatasource.php b/src/applications/people/typeahead/PhabricatorPeopleDatasource.php index cdd68988a9..2cd337cacc 100644 --- a/src/applications/people/typeahead/PhabricatorPeopleDatasource.php +++ b/src/applications/people/typeahead/PhabricatorPeopleDatasource.php @@ -59,12 +59,15 @@ final class PhabricatorPeopleDatasource $closed = pht('Mailing List'); } + $username = $user->getUsername(); + $result = id(new PhabricatorTypeaheadResult()) ->setName($user->getFullName()) - ->setURI('/p/'.$user->getUsername()) + ->setURI('/p/'.$username.'/') ->setPHID($user->getPHID()) - ->setPriorityString($user->getUsername()) + ->setPriorityString($username) ->setPriorityType('user') + ->setAutocomplete('@'.$username) ->setClosed($closed); if ($user->getIsMailingList()) { diff --git a/src/applications/phame/storage/PhameBlog.php b/src/applications/phame/storage/PhameBlog.php index 5b5b128ae6..d9b9bdb41d 100644 --- a/src/applications/phame/storage/PhameBlog.php +++ b/src/applications/phame/storage/PhameBlog.php @@ -340,10 +340,6 @@ final class PhameBlog extends PhameDAO return true; } - public function shouldAllowSubscription($phid) { - return true; - } - /* -( PhabricatorConduitResultInterface )---------------------------------- */ diff --git a/src/applications/phame/storage/PhamePost.php b/src/applications/phame/storage/PhamePost.php index 57519bd2f1..01dd71e88d 100644 --- a/src/applications/phame/storage/PhamePost.php +++ b/src/applications/phame/storage/PhamePost.php @@ -286,10 +286,6 @@ final class PhamePost extends PhameDAO return true; } - public function shouldAllowSubscription($phid) { - return true; - } - /* -( PhabricatorConduitResultInterface )---------------------------------- */ diff --git a/src/applications/phame/view/PhameBlogListView.php b/src/applications/phame/view/PhameBlogListView.php index 6f42da77fe..ae936442b0 100644 --- a/src/applications/phame/view/PhameBlogListView.php +++ b/src/applications/phame/view/PhameBlogListView.php @@ -89,7 +89,12 @@ final class PhameBlogListView extends AphrontTagView { ), pht('Blogs'))); - return array($header, $list); + return id(new PHUIBoxView()) + ->appendChild($header) + ->appendChild($list) + ->addClass('pl') + ->setColor(PHUIBoxView::BLUE); + } } diff --git a/src/applications/phame/view/PhameDraftListView.php b/src/applications/phame/view/PhameDraftListView.php index 558bf19b52..68bb56cabf 100644 --- a/src/applications/phame/view/PhameDraftListView.php +++ b/src/applications/phame/view/PhameDraftListView.php @@ -92,7 +92,11 @@ final class PhameDraftListView extends AphrontTagView { ), pht('Drafts'))); - return array($header, $list); + return id(new PHUIBoxView()) + ->appendChild($header) + ->appendChild($list) + ->addClass('pl') + ->setColor(PHUIBoxView::BLUE); } } diff --git a/src/applications/pholio/storage/PholioMock.php b/src/applications/pholio/storage/PholioMock.php index 6316d92cb9..c817b7f32b 100644 --- a/src/applications/pholio/storage/PholioMock.php +++ b/src/applications/pholio/storage/PholioMock.php @@ -188,10 +188,6 @@ final class PholioMock extends PholioDAO return true; } - public function shouldAllowSubscription($phid) { - return true; - } - /* -( PhabricatorPolicyInterface Implementation )-------------------------- */ diff --git a/src/applications/pholio/view/PholioMockImagesView.php b/src/applications/pholio/view/PholioMockImagesView.php index cf8d0c6143..8430ada3d4 100644 --- a/src/applications/pholio/view/PholioMockImagesView.php +++ b/src/applications/pholio/view/PholioMockImagesView.php @@ -68,11 +68,9 @@ final class PholioMockImagesView extends AphrontView { // TODO: We could maybe do a better job with tailoring this, which is the // image shown on the review stage. - $default_name = 'image-100x100.png'; - $builtins = PhabricatorFile::loadBuiltins( - $this->getUser(), - array($default_name)); - $default = $builtins[$default_name]; + $viewer = $this->getUser(); + + $default = PhabricatorFile::loadBuiltin($viewer, 'image-100x100.png'); $engine = id(new PhabricatorMarkupEngine()) ->setViewer($this->getUser()); diff --git a/src/applications/phriction/storage/PhrictionDocument.php b/src/applications/phriction/storage/PhrictionDocument.php index 3c883625b0..915cfed1eb 100644 --- a/src/applications/phriction/storage/PhrictionDocument.php +++ b/src/applications/phriction/storage/PhrictionDocument.php @@ -198,10 +198,6 @@ final class PhrictionDocument extends PhrictionDAO return true; } - public function shouldAllowSubscription($phid) { - return true; - } - /* -( PhabricatorApplicationTransactionInterface )------------------------- */ diff --git a/src/applications/phurl/storage/PhabricatorPhurlURL.php b/src/applications/phurl/storage/PhabricatorPhurlURL.php index 7df1d241a7..30a3b0b93b 100644 --- a/src/applications/phurl/storage/PhabricatorPhurlURL.php +++ b/src/applications/phurl/storage/PhabricatorPhurlURL.php @@ -173,10 +173,6 @@ final class PhabricatorPhurlURL extends PhabricatorPhurlDAO return true; } - public function shouldAllowSubscription($phid) { - return true; - } - /* -( PhabricatorTokenReceiverInterface )---------------------------------- */ diff --git a/src/applications/ponder/query/PonderQuestionQuery.php b/src/applications/ponder/query/PonderQuestionQuery.php index 480f2c3296..9762f925f5 100644 --- a/src/applications/ponder/query/PonderQuestionQuery.php +++ b/src/applications/ponder/query/PonderQuestionQuery.php @@ -129,13 +129,13 @@ final class PonderQuestionQuery return $questions; } - protected function buildJoinClauseParts(AphrontDatabaseConnection $conn_r) { - $joins = array(); + protected function buildJoinClauseParts(AphrontDatabaseConnection $conn) { + $joins = parent::buildJoinClauseParts($conn); if ($this->answererPHIDs) { $answer_table = new PonderAnswer(); $joins[] = qsprintf( - $conn_r, + $conn, 'JOIN %T a ON a.questionID = q.id AND a.authorPHID IN (%Ls)', $answer_table->getTableName(), $this->answererPHIDs); diff --git a/src/applications/ponder/storage/PonderAnswer.php b/src/applications/ponder/storage/PonderAnswer.php index 722fee8eec..4da222d5a5 100644 --- a/src/applications/ponder/storage/PonderAnswer.php +++ b/src/applications/ponder/storage/PonderAnswer.php @@ -253,10 +253,6 @@ final class PonderAnswer extends PonderDAO return true; } - public function shouldAllowSubscription($phid) { - return true; - } - /* -( PhabricatorDestructibleInterface )----------------------------------- */ diff --git a/src/applications/ponder/storage/PonderQuestion.php b/src/applications/ponder/storage/PonderQuestion.php index bbce081d88..5ab719e3ac 100644 --- a/src/applications/ponder/storage/PonderQuestion.php +++ b/src/applications/ponder/storage/PonderQuestion.php @@ -252,10 +252,6 @@ final class PonderQuestion extends PonderDAO return true; } - public function shouldAllowSubscription($phid) { - return true; - } - /* -( PhabricatorTokenReceiverInterface )---------------------------------- */ diff --git a/src/applications/project/__tests__/PhabricatorProjectCoreTestCase.php b/src/applications/project/__tests__/PhabricatorProjectCoreTestCase.php index 36c78386f3..3bd38353f6 100644 --- a/src/applications/project/__tests__/PhabricatorProjectCoreTestCase.php +++ b/src/applications/project/__tests__/PhabricatorProjectCoreTestCase.php @@ -113,6 +113,38 @@ final class PhabricatorProjectCoreTestCase extends PhabricatorTestCase { $this->assertTrue($caught instanceof Exception); } + public function testAncestorMembers() { + $user1 = $this->createUser(); + $user1->save(); + + $user2 = $this->createUser(); + $user2->save(); + + $parent = $this->createProject($user1); + $child = $this->createProject($user1, $parent); + + $this->joinProject($child, $user1); + $this->joinProject($child, $user2); + + $project = id(new PhabricatorProjectQuery()) + ->setViewer($user1) + ->withPHIDs(array($child->getPHID())) + ->needAncestorMembers(true) + ->executeOne(); + + $members = array_fuse($project->getParentProject()->getMemberPHIDs()); + ksort($members); + + $expect = array_fuse( + array( + $user1->getPHID(), + $user2->getPHID(), + )); + ksort($expect); + + $this->assertEqual($expect, $members); + } + public function testAncestryQueries() { $user = $this->createUser(); $user->save(); @@ -577,24 +609,6 @@ final class PhabricatorProjectCoreTestCase extends PhabricatorTestCase { $this->assertEqual($expect, $actual); } - private function attemptProjectEdit( - PhabricatorProject $proj, - PhabricatorUser $user, - $skip_refresh = false) { - - $proj = $this->refreshProject($proj, $user, true); - - $new_name = $proj->getName().' '.mt_rand(); - - $xaction = new PhabricatorProjectTransaction(); - $xaction->setTransactionType(PhabricatorProjectTransaction::TYPE_NAME); - $xaction->setNewValue($new_name); - - $this->applyTransactions($proj, $user, array($xaction)); - - return true; - } - public function testJoinLeaveProject() { $user = $this->createUser(); $user->save(); @@ -794,6 +808,25 @@ final class PhabricatorProjectCoreTestCase extends PhabricatorTestCase { pht('Engineering + Scan')); } + private function attemptProjectEdit( + PhabricatorProject $proj, + PhabricatorUser $user, + $skip_refresh = false) { + + $proj = $this->refreshProject($proj, $user, true); + + $new_name = $proj->getName().' '.mt_rand(); + + $xaction = new PhabricatorProjectTransaction(); + $xaction->setTransactionType(PhabricatorProjectTransaction::TYPE_NAME); + $xaction->setNewValue($new_name); + + $this->applyTransactions($proj, $user, array($xaction)); + + return true; + } + + private function newTask( PhabricatorUser $viewer, array $projects, diff --git a/src/applications/project/application/PhabricatorProjectApplication.php b/src/applications/project/application/PhabricatorProjectApplication.php index e3732f2b31..60e4412273 100644 --- a/src/applications/project/application/PhabricatorProjectApplication.php +++ b/src/applications/project/application/PhabricatorProjectApplication.php @@ -48,13 +48,13 @@ final class PhabricatorProjectApplication extends PhabricatorApplication { 'lock/(?P[1-9]\d*)/' => 'PhabricatorProjectLockController', 'members/(?P[1-9]\d*)/' - => 'PhabricatorProjectMembersEditController', - 'members/(?P[1-9]\d*)/remove/' + => 'PhabricatorProjectMembersViewController', + 'members/(?P[1-9]\d*)/add/' + => 'PhabricatorProjectMembersAddController', + '(?Pmembers|watchers)/(?P[1-9]\d*)/remove/' => 'PhabricatorProjectMembersRemoveController', 'profile/(?P[1-9]\d*)/' => 'PhabricatorProjectProfileController', - 'feed/(?P[1-9]\d*)/' - => 'PhabricatorProjectFeedController', 'view/(?P[1-9]\d*)/' => 'PhabricatorProjectViewController', 'picture/(?P[1-9]\d*)/' @@ -89,6 +89,8 @@ final class PhabricatorProjectApplication extends PhabricatorApplication { 'history/(?P[1-9]\d*)/' => 'PhabricatorProjectHistoryController', '(?Pwatch|unwatch)/(?P[1-9]\d*)/' => 'PhabricatorProjectWatchController', + 'silence/(?P[1-9]\d*)/' + => 'PhabricatorProjectSilenceController', ), '/tag/' => array( '(?P[^/]+)/' => 'PhabricatorProjectViewController', @@ -133,4 +135,13 @@ final class PhabricatorProjectApplication extends PhabricatorApplication { ); } + public function getHelpDocumentationArticles(PhabricatorUser $viewer) { + return array( + array( + 'name' => pht('Projects User Guide'), + 'href' => PhabricatorEnv::getDoclink('Projects User Guide'), + ), + ); + } + } diff --git a/src/applications/project/config/PhabricatorProjectColorsConfigOptionType.php b/src/applications/project/config/PhabricatorProjectColorsConfigOptionType.php new file mode 100644 index 0000000000..4cd8c09bbc --- /dev/null +++ b/src/applications/project/config/PhabricatorProjectColorsConfigOptionType.php @@ -0,0 +1,10 @@ +deformat(pht(<<deformat(pht(<< true, @@ -76,6 +97,9 @@ EOTEXT $this->newOption('projects.icons', $icons_type, $default_icons) ->setSummary(pht('Adjust project icons.')) ->setDescription($icons_description), + $this->newOption('projects.colors', $colors_type, $default_colors) + ->setSummary(pht('Adjust project colors.')) + ->setDescription($colors_description), ); } diff --git a/src/applications/project/config/PhabricatorProjectTypeConfigOptionType.php b/src/applications/project/config/PhabricatorProjectIconsConfigOptionType.php similarity index 79% rename from src/applications/project/config/PhabricatorProjectTypeConfigOptionType.php rename to src/applications/project/config/PhabricatorProjectIconsConfigOptionType.php index 8c65dfe35a..054a696a44 100644 --- a/src/applications/project/config/PhabricatorProjectTypeConfigOptionType.php +++ b/src/applications/project/config/PhabricatorProjectIconsConfigOptionType.php @@ -1,6 +1,6 @@ getApplicationURI('profile/'.$project->getID().'/'); + $edit_uri = $this->getApplicationURI('history/'.$project->getID().'/'); if ($request->isFormPost()) { if ($project->isArchived()) { diff --git a/src/applications/project/controller/PhabricatorProjectBoardImportController.php b/src/applications/project/controller/PhabricatorProjectBoardImportController.php index 46877b9e14..8df4e8b810 100644 --- a/src/applications/project/controller/PhabricatorProjectBoardImportController.php +++ b/src/applications/project/controller/PhabricatorProjectBoardImportController.php @@ -57,6 +57,9 @@ final class PhabricatorProjectBoardImportController ->setProperties($import_column->getProperties()) ->save(); } + + $project->setHasWorkboard(1)->save(); + $table->saveTransaction(); return id(new AphrontRedirectResponse())->setURI($board_uri); diff --git a/src/applications/project/controller/PhabricatorProjectBoardViewController.php b/src/applications/project/controller/PhabricatorProjectBoardViewController.php index 571d5b866d..9b7b76e62c 100644 --- a/src/applications/project/controller/PhabricatorProjectBoardViewController.php +++ b/src/applications/project/controller/PhabricatorProjectBoardViewController.php @@ -19,50 +19,16 @@ final class PhabricatorProjectBoardViewController public function handleRequest(AphrontRequest $request) { $viewer = $request->getUser(); - $id = $request->getURIData('id'); - $show_hidden = $request->getBool('hidden'); - $this->showHidden = $show_hidden; - - $project = id(new PhabricatorProjectQuery()) - ->setViewer($viewer) - ->needImages(true); - $id = $request->getURIData('id'); - $slug = $request->getURIData('slug'); - if ($slug) { - $project->withSlugs(array($slug)); - } else { - $project->withIDs(array($id)); - } - $project = $project->executeOne(); - if (!$project) { - return new Aphront404Response(); + $response = $this->loadProject(); + if ($response) { + return $response; } - $this->setProject($project); - $this->id = $project->getID(); + $project = $this->getProject(); - $sort_key = $request->getStr('order'); - switch ($sort_key) { - case PhabricatorProjectColumn::ORDER_NATURAL: - case PhabricatorProjectColumn::ORDER_PRIORITY: - break; - default: - $sort_key = PhabricatorProjectColumn::DEFAULT_ORDER; - break; - } - $this->sortKey = $sort_key; - - $column_query = id(new PhabricatorProjectColumnQuery()) - ->setViewer($viewer) - ->withProjectPHIDs(array($project->getPHID())); - if (!$show_hidden) { - $column_query->withStatuses( - array(PhabricatorProjectColumn::STATUS_ACTIVE)); - } - - $columns = $column_query->execute(); - $columns = mpull($columns, null, 'getSequence'); + $this->readRequestState(); + $columns = $this->loadColumns($project); // TODO: Expand the checks here if we add the ability // to hide the Backlog column @@ -72,32 +38,31 @@ final class PhabricatorProjectBoardViewController $project, PhabricatorPolicyCapability::CAN_EDIT); if (!$can_edit) { - return $this->noAccessDialog($project); + $content = $this->buildNoAccessContent($project); + } else { + $content = $this->buildInitializeContent($project); } - switch ($request->getStr('initialize-type')) { - case 'backlog-only': - $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); - $column = PhabricatorProjectColumn::initializeNewColumn($viewer) - ->setSequence(0) - ->setProperty('isDefault', true) - ->setProjectPHID($project->getPHID()) - ->save(); - $column->attachProject($project); - $columns[0] = $column; - unset($unguarded); - break; - case 'import': - return id(new AphrontRedirectResponse()) - ->setURI( - $this->getApplicationURI('board/'.$project->getID().'/import/')); - break; - default: - return $this->initializeWorkboardDialog($project); - break; - } - } - ksort($columns); + if ($content instanceof AphrontResponse) { + return $content; + } + + $nav = $this->getProfileMenu(); + $nav->selectFilter(PhabricatorProject::PANEL_WORKBOARD); + + $crumbs = $this->buildApplicationCrumbs(); + $crumbs->addTextCrumb(pht('Workboard')); + + return $this->newPage() + ->setTitle( + array( + pht('Workboard'), + $project->getName(), + )) + ->setNavigation($nav) + ->setCrumbs($crumbs) + ->appendChild($content); + } $board_uri = $this->getApplicationURI('board/'.$project->getID().'/'); @@ -350,7 +315,7 @@ final class PhabricatorProjectBoardViewController $sort_menu = $this->buildSortMenu( $viewer, - $sort_key); + $this->sortKey); $filter_menu = $this->buildFilterMenu( $viewer, @@ -358,7 +323,7 @@ final class PhabricatorProjectBoardViewController $engine, $query_key); - $manage_menu = $this->buildManageMenu($project, $show_hidden); + $manage_menu = $this->buildManageMenu($project, $this->showHidden); $header_link = phutil_tag( 'a', @@ -402,6 +367,44 @@ final class PhabricatorProjectBoardViewController )); } + private function readRequestState() { + $request = $this->getRequest(); + $project = $this->getProject(); + + $this->showHidden = $request->getBool('hidden'); + $this->id = $project->getID(); + + $sort_key = $request->getStr('order'); + switch ($sort_key) { + case PhabricatorProjectColumn::ORDER_NATURAL: + case PhabricatorProjectColumn::ORDER_PRIORITY: + break; + default: + $sort_key = PhabricatorProjectColumn::DEFAULT_ORDER; + break; + } + $this->sortKey = $sort_key; + } + + private function loadColumns(PhabricatorProject $project) { + $viewer = $this->getViewer(); + + $column_query = id(new PhabricatorProjectColumnQuery()) + ->setViewer($viewer) + ->withProjectPHIDs(array($project->getPHID())); + + if (!$this->showHidden) { + $column_query->withStatuses( + array(PhabricatorProjectColumn::STATUS_ACTIVE)); + } + + $columns = $column_query->execute(); + $columns = mpull($columns, null, 'getSequence'); + ksort($columns); + + return $columns; + } + private function buildSortMenu( PhabricatorUser $viewer, $sort_key) { @@ -697,47 +700,6 @@ final class PhabricatorProjectBoardViewController return $column_button; } - private function initializeWorkboardDialog(PhabricatorProject $project) { - - $instructions = pht('This workboard has not been setup yet.'); - $new_selector = id(new AphrontFormRadioButtonControl()) - ->setName('initialize-type') - ->setValue('backlog-only') - ->addButton( - 'backlog-only', - pht('New Empty Board'), - pht('Create a new board with just a backlog column.')) - ->addButton( - 'import', - pht('Import Columns'), - pht('Import board columns from another project.')); - - $dialog = id(new AphrontDialogView()) - ->setUser($this->getRequest()->getUser()) - ->setTitle(pht('New Workboard')) - ->addSubmitButton('Continue') - ->addCancelButton($this->getApplicationURI('view/'.$project->getID().'/')) - ->appendParagraph($instructions) - ->appendChild($new_selector); - - return id(new AphrontDialogResponse()) - ->setDialog($dialog); - } - - private function noAccessDialog(PhabricatorProject $project) { - - $instructions = pht('This workboard has not been setup yet.'); - - $dialog = id(new AphrontDialogView()) - ->setUser($this->getRequest()->getUser()) - ->setTitle(pht('No Workboard')) - ->addCancelButton($this->getApplicationURI('view/'.$project->getID().'/')) - ->appendParagraph($instructions); - - return id(new AphrontDialogResponse()) - ->setDialog($dialog); - } - /** * Add current state parameters (like order and the visibility of hidden @@ -786,4 +748,98 @@ final class PhabricatorProjectBoardViewController return $create_uri; } + + private function buildInitializeContent(PhabricatorProject $project) { + $request = $this->getRequest(); + $viewer = $this->getViewer(); + + $type = $request->getStr('initialize-type'); + + $id = $project->getID(); + + $profile_uri = $this->getApplicationURI("profile/{$id}/"); + $board_uri = $this->getApplicationURI("board/{$id}/"); + $import_uri = $this->getApplicationURI("board/{$id}/import/"); + + $set_default = $request->getBool('default'); + if ($set_default) { + $this + ->getProfilePanelEngine() + ->adjustDefault(PhabricatorProject::PANEL_WORKBOARD); + } + + if ($request->isFormPost()) { + if ($type == 'backlog-only') { + $column = PhabricatorProjectColumn::initializeNewColumn($viewer) + ->setSequence(0) + ->setProperty('isDefault', true) + ->setProjectPHID($project->getPHID()) + ->save(); + + $project->setHasWorkboard(1)->save(); + + return id(new AphrontRedirectResponse()) + ->setURI($board_uri); + } else { + return id(new AphrontRedirectResponse()) + ->setURI($import_uri); + } + } + + $new_selector = id(new AphrontFormRadioButtonControl()) + ->setLabel(pht('Columns')) + ->setName('initialize-type') + ->setValue('backlog-only') + ->addButton( + 'backlog-only', + pht('New Empty Board'), + pht('Create a new board with just a backlog column.')) + ->addButton( + 'import', + pht('Import Columns'), + pht('Import board columns from another project.')); + + $default_checkbox = id(new AphrontFormCheckboxControl()) + ->setLabel(pht('Make Default')) + ->addCheckbox( + 'default', + 1, + pht('Make the workboard the default view for this project.'), + true); + + $form = id(new AphrontFormView()) + ->setUser($viewer) + ->appendRemarkupInstructions( + pht('The workboard for this project has not been created yet.')) + ->appendControl($new_selector) + ->appendControl($default_checkbox) + ->appendControl( + id(new AphrontFormSubmitControl()) + ->addCancelButton($profile_uri) + ->setValue(pht('Create Workboard'))); + + $box = id(new PHUIObjectBoxView()) + ->setHeaderText(pht('Create Workboard')) + ->setForm($form); + + return $box; + } + + private function buildNoAccessContent(PhabricatorProject $project) { + $viewer = $this->getViewer(); + + $id = $project->getID(); + + $profile_uri = $this->getApplicationURI("profile/{$id}/"); + + return $this->newDialog() + ->setTitle(pht('Unable to Create Workboard')) + ->appendParagraph( + pht( + 'The workboard for this project has not been created yet, '. + 'but you do not have permission to create it. Only users '. + 'who can edit this project can create a workboard for it.')) + ->addCancelButton($profile_uri); + } + } diff --git a/src/applications/project/controller/PhabricatorProjectController.php b/src/applications/project/controller/PhabricatorProjectController.php index 9c6fa2f4e2..8687e0a3a7 100644 --- a/src/applications/project/controller/PhabricatorProjectController.php +++ b/src/applications/project/controller/PhabricatorProjectController.php @@ -4,6 +4,7 @@ abstract class PhabricatorProjectController extends PhabricatorController { private $project; private $profileMenu; + private $profilePanelEngine; protected function setProject(PhabricatorProject $project) { $this->project = $project; @@ -98,14 +99,8 @@ abstract class PhabricatorProjectController extends PhabricatorController { protected function getProfileMenu() { if (!$this->profileMenu) { - $project = $this->getProject(); - if ($project) { - $viewer = $this->getViewer(); - - $engine = id(new PhabricatorProfilePanelEngine()) - ->setViewer($viewer) - ->setProfileObject($project); - + $engine = $this->getProfilePanelEngine(); + if ($engine) { $this->profileMenu = $engine->buildNavigation(); } } @@ -131,4 +126,25 @@ abstract class PhabricatorProjectController extends PhabricatorController { return $crumbs; } + protected function getProfilePanelEngine() { + if (!$this->profilePanelEngine) { + $viewer = $this->getViewer(); + $project = $this->getProject(); + if ($project) { + $engine = id(new PhabricatorProjectProfilePanelEngine()) + ->setViewer($viewer) + ->setController($this) + ->setProfileObject($project); + $this->profilePanelEngine = $engine; + } + } + return $this->profilePanelEngine; + } + + protected function setProfilePanelEngine( + PhabricatorProjectProfilePanelEngine $engine) { + $this->profilePanelEngine = $engine; + return $this; + } + } diff --git a/src/applications/project/controller/PhabricatorProjectEditPictureController.php b/src/applications/project/controller/PhabricatorProjectEditPictureController.php index 8828bfae57..b0c013dadc 100644 --- a/src/applications/project/controller/PhabricatorProjectEditPictureController.php +++ b/src/applications/project/controller/PhabricatorProjectEditPictureController.php @@ -23,8 +23,8 @@ final class PhabricatorProjectEditPictureController $this->setProject($project); - $edit_uri = $this->getApplicationURI('profile/'.$project->getID().'/'); - $view_uri = $this->getApplicationURI('profile/'.$project->getID().'/'); + $edit_uri = $this->getApplicationURI('history/'.$project->getID().'/'); + $view_uri = $this->getApplicationURI('history/'.$project->getID().'/'); $supported_formats = PhabricatorFile::getTransformableImageFormats(); $e_file = true; @@ -123,7 +123,7 @@ final class PhabricatorProjectEditPictureController $images[PhabricatorPHIDConstants::PHID_VOID] = array( 'uri' => $default_image->getBestURI(), - 'tip' => pht('Default Picture'), + 'tip' => pht('No Picture'), ); require_celerity_resource('people-profile-css'); @@ -181,7 +181,11 @@ final class PhabricatorProjectEditPictureController $form->appendChild( id(new AphrontFormMarkupControl()) ->setLabel(pht('Use Picture')) - ->setValue($buttons)); + ->setValue( + array( + $this->renderDefaultForm($project), + $buttons, + ))); $launch_id = celerity_generate_unique_node_id(); $input_id = celerity_generate_unique_node_id(); @@ -226,38 +230,6 @@ final class PhabricatorProjectEditPictureController ->setLabel(pht('Quick Create')) ->setValue($compose_form)); - $default_button = javelin_tag( - 'button', - array( - 'class' => 'grey', - ), - pht('Use Project Icon')); - - $default_input = javelin_tag( - 'input', - array( - 'type' => 'hidden', - 'name' => 'projectPHID', - 'value' => $project->getPHID(), - )); - - $default_form = phabricator_form( - $viewer, - array( - 'class' => 'profile-image-form', - 'method' => 'POST', - 'action' => '/file/compose/', - ), - array( - $default_input, - $default_button, - )); - - $form->appendChild( - id(new AphrontFormMarkupControl()) - ->setLabel(pht('Use Default')) - ->setValue($default_form)); - $upload_form = id(new AphrontFormView()) ->setUser($viewer) ->setEncType('multipart/form-data') @@ -294,4 +266,69 @@ final class PhabricatorProjectEditPictureController $upload_box, )); } + + private function renderDefaultForm(PhabricatorProject $project) { + $viewer = $this->getViewer(); + $compose_color = $project->getDisplayIconComposeColor(); + $compose_icon = $project->getDisplayIconComposeIcon(); + + $default_builtin = id(new PhabricatorFilesComposeIconBuiltinFile()) + ->setColor($compose_color) + ->setIcon($compose_icon); + + $file_builtins = PhabricatorFile::loadBuiltins( + $viewer, + array($default_builtin)); + + $file_builtin = head($file_builtins); + + $default_button = javelin_tag( + 'button', + array( + 'class' => 'grey profile-image-button', + 'sigil' => 'has-tooltip', + 'meta' => array( + 'tip' => pht('Use Icon and Color'), + 'size' => 300, + ), + ), + phutil_tag( + 'img', + array( + 'height' => 50, + 'width' => 50, + 'src' => $file_builtin->getBestURI(), + ))); + + $inputs = array( + 'projectPHID' => $project->getPHID(), + 'icon' => $compose_icon, + 'color' => $compose_color, + ); + + foreach ($inputs as $key => $value) { + $inputs[$key] = javelin_tag( + 'input', + array( + 'type' => 'hidden', + 'name' => $key, + 'value' => $value, + )); + } + + $default_form = phabricator_form( + $viewer, + array( + 'class' => 'profile-image-form', + 'method' => 'POST', + 'action' => '/file/compose/', + ), + array( + $inputs, + $default_button, + )); + + return $default_form; + } + } diff --git a/src/applications/project/controller/PhabricatorProjectFeedController.php b/src/applications/project/controller/PhabricatorProjectFeedController.php deleted file mode 100644 index a108384088..0000000000 --- a/src/applications/project/controller/PhabricatorProjectFeedController.php +++ /dev/null @@ -1,62 +0,0 @@ -getUser(); - - $response = $this->loadProject(); - if ($response) { - return $response; - } - - $project = $this->getProject(); - $id = $project->getID(); - - $stories = id(new PhabricatorFeedQuery()) - ->setViewer($viewer) - ->setFilterPHIDs( - array( - $project->getPHID(), - )) - ->setLimit(50) - ->execute(); - - $feed = $this->renderStories($stories); - - $box = id(new PHUIObjectBoxView()) - ->setHeaderText(pht('Project Activity')) - ->appendChild($feed); - - $nav = $this->getProfileMenu(); - $nav->selectFilter('feed'); - - $crumbs = $this->buildApplicationCrumbs(); - $crumbs->addTextCrumb(pht('Feed')); - - return $this->newPage() - ->setNavigation($nav) - ->setCrumbs($crumbs) - ->setTitle(array($project->getName(), pht('Feed'))) - ->appendChild($box); - } - - private function renderStories(array $stories) { - assert_instances_of($stories, 'PhabricatorFeedStory'); - - $builder = new PhabricatorFeedBuilder($stories); - $builder->setUser($this->getRequest()->getUser()); - $builder->setShowHovercards(true); - $view = $builder->buildView(); - - return phutil_tag_div( - 'profile-feed', - $view->render()); - } - -} diff --git a/src/applications/project/controller/PhabricatorProjectHistoryController.php b/src/applications/project/controller/PhabricatorProjectHistoryController.php new file mode 100644 index 0000000000..aa58e081f4 --- /dev/null +++ b/src/applications/project/controller/PhabricatorProjectHistoryController.php @@ -0,0 +1,133 @@ +loadProject(); + if ($response) { + return $response; + } + + $viewer = $request->getUser(); + $project = $this->getProject(); + $id = $project->getID(); + $picture = $project->getProfileImageURI(); + + $header = id(new PHUIHeaderView()) + ->setHeader(pht('Project History')) + ->setUser($viewer) + ->setPolicyObject($project) + ->setImage($picture); + + if ($project->getStatus() == PhabricatorProjectStatus::STATUS_ACTIVE) { + $header->setStatus('fa-check', 'bluegrey', pht('Active')); + } else { + $header->setStatus('fa-ban', 'red', pht('Archived')); + } + + $actions = $this->buildActionListView($project); + $properties = $this->buildPropertyListView($project, $actions); + + $object_box = id(new PHUIObjectBoxView()) + ->setHeader($header) + ->addPropertyList($properties); + + $timeline = $this->buildTransactionTimeline( + $project, + new PhabricatorProjectTransactionQuery()); + $timeline->setShouldTerminate(true); + + $nav = $this->getProfileMenu(); + $nav->selectFilter(PhabricatorProject::PANEL_PROFILE); + + $crumbs = $this->buildApplicationCrumbs(); + $crumbs->addTextCrumb(pht('History')); + + return $this->newPage() + ->setNavigation($nav) + ->setCrumbs($crumbs) + ->setTitle($project->getName()) + ->appendChild( + array( + $object_box, + $timeline, + )); + } + + private function buildActionListView(PhabricatorProject $project) { + $request = $this->getRequest(); + $viewer = $request->getUser(); + + $id = $project->getID(); + + $view = id(new PhabricatorActionListView()) + ->setUser($viewer); + + $can_edit = PhabricatorPolicyFilter::hasCapability( + $viewer, + $project, + PhabricatorPolicyCapability::CAN_EDIT); + + $view->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Back to Profile')) + ->setIcon('fa-chevron-left') + ->setHref($project->getURI())); + + $view->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Edit Details')) + ->setIcon('fa-pencil') + ->setHref($this->getApplicationURI("edit/{$id}/")) + ->setDisabled(!$can_edit) + ->setWorkflow(!$can_edit)); + + $view->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Edit Picture')) + ->setIcon('fa-picture-o') + ->setHref($this->getApplicationURI("picture/{$id}/")) + ->setDisabled(!$can_edit) + ->setWorkflow(!$can_edit)); + + if ($project->isArchived()) { + $view->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Activate Project')) + ->setIcon('fa-check') + ->setHref($this->getApplicationURI("archive/{$id}/")) + ->setDisabled(!$can_edit) + ->setWorkflow(true)); + } else { + $view->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Archive Project')) + ->setIcon('fa-ban') + ->setHref($this->getApplicationURI("archive/{$id}/")) + ->setDisabled(!$can_edit) + ->setWorkflow(true)); + } + + return $view; + } + + private function buildPropertyListView( + PhabricatorProject $project, + PhabricatorActionListView $actions) { + $request = $this->getRequest(); + $viewer = $request->getUser(); + + $view = id(new PHUIPropertyListView()) + ->setUser($viewer) + ->setActionList($actions); + + return $view; + } + + +} diff --git a/src/applications/project/controller/PhabricatorProjectLockController.php b/src/applications/project/controller/PhabricatorProjectLockController.php index 744be32f99..b9b56bde10 100644 --- a/src/applications/project/controller/PhabricatorProjectLockController.php +++ b/src/applications/project/controller/PhabricatorProjectLockController.php @@ -27,7 +27,16 @@ final class PhabricatorProjectLockController return new Aphront404Response(); } - $done_uri = $project->getURI(); + $done_uri = "/project/members/{$id}/"; + + if (!$project->supportsEditMembers()) { + return $this->newDialog() + ->setTitle(pht('Membership Immutable')) + ->appendChild( + pht('This project does not support editing membership.')) + ->addCancelButton($done_uri); + } + $is_locked = $project->getIsMembershipLocked(); if ($request->isFormPost()) { diff --git a/src/applications/project/controller/PhabricatorProjectMembersAddController.php b/src/applications/project/controller/PhabricatorProjectMembersAddController.php new file mode 100644 index 0000000000..bd1631ee92 --- /dev/null +++ b/src/applications/project/controller/PhabricatorProjectMembersAddController.php @@ -0,0 +1,72 @@ +getViewer(); + $id = $request->getURIData('id'); + + $project = id(new PhabricatorProjectQuery()) + ->setViewer($viewer) + ->withIDs(array($id)) + ->requireCapabilities( + array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + )) + ->executeOne(); + if (!$project) { + return new Aphront404Response(); + } + + $this->setProject($project); + + if (!$project->supportsEditMembers()) { + return new Aphront404Response(); + } + + $done_uri = "/project/members/{$id}/"; + + if ($request->isFormPost()) { + $member_phids = $request->getArr('memberPHIDs'); + + $type_member = PhabricatorProjectProjectHasMemberEdgeType::EDGECONST; + + $xactions = array(); + + $xactions[] = id(new PhabricatorProjectTransaction()) + ->setTransactionType(PhabricatorTransactions::TYPE_EDGE) + ->setMetadataValue('edge:type', $type_member) + ->setNewValue( + array( + '+' => array_fuse($member_phids), + )); + + $editor = id(new PhabricatorProjectTransactionEditor($project)) + ->setActor($viewer) + ->setContentSourceFromRequest($request) + ->setContinueOnNoEffect(true) + ->setContinueOnMissingFields(true) + ->applyTransactions($project, $xactions); + + return id(new AphrontRedirectResponse()) + ->setURI($done_uri); + } + + $form = id(new AphrontFormView()) + ->setUser($viewer) + ->appendControl( + id(new AphrontFormTokenizerControl()) + ->setName('memberPHIDs') + ->setLabel(pht('Members')) + ->setDatasource(new PhabricatorPeopleDatasource())); + + return $this->newDialog() + ->setTitle(pht('Add Members')) + ->appendForm($form) + ->addCancelButton($done_uri) + ->addSubmitButton(pht('Add Members')); + } + +} diff --git a/src/applications/project/controller/PhabricatorProjectMembersEditController.php b/src/applications/project/controller/PhabricatorProjectMembersEditController.php deleted file mode 100644 index f485e2997a..0000000000 --- a/src/applications/project/controller/PhabricatorProjectMembersEditController.php +++ /dev/null @@ -1,156 +0,0 @@ -getViewer(); - $id = $request->getURIData('id'); - - $project = id(new PhabricatorProjectQuery()) - ->setViewer($viewer) - ->withIDs(array($id)) - ->needMembers(true) - ->needImages(true) - ->executeOne(); - if (!$project) { - return new Aphront404Response(); - } - - $this->setProject($project); - - $member_phids = $project->getMemberPHIDs(); - - if ($request->isFormPost()) { - $member_spec = array(); - - $remove = $request->getStr('remove'); - if ($remove) { - $member_spec['-'] = array_fuse(array($remove)); - } - - $add_members = $request->getArr('phids'); - if ($add_members) { - $member_spec['+'] = array_fuse($add_members); - } - - $type_member = PhabricatorProjectProjectHasMemberEdgeType::EDGECONST; - - $xactions = array(); - - $xactions[] = id(new PhabricatorProjectTransaction()) - ->setTransactionType(PhabricatorTransactions::TYPE_EDGE) - ->setMetadataValue('edge:type', $type_member) - ->setNewValue($member_spec); - - $editor = id(new PhabricatorProjectTransactionEditor($project)) - ->setActor($viewer) - ->setContentSourceFromRequest($request) - ->setContinueOnNoEffect(true) - ->setContinueOnMissingFields(true) - ->applyTransactions($project, $xactions); - - return id(new AphrontRedirectResponse()) - ->setURI($request->getRequestURI()); - } - - $member_phids = array_reverse($member_phids); - $handles = $this->loadViewerHandles($member_phids); - - $state = array(); - foreach ($handles as $handle) { - $state[] = array( - 'phid' => $handle->getPHID(), - 'name' => $handle->getFullName(), - ); - } - - $can_edit = PhabricatorPolicyFilter::hasCapability( - $viewer, - $project, - PhabricatorPolicyCapability::CAN_EDIT); - - $supports_edit = $project->supportsEditMembers(); - - $form_box = null; - $title = pht('Add Members'); - if ($can_edit && $supports_edit) { - $header_name = pht('Edit Members'); - $view_uri = $this->getApplicationURI('profile/'.$project->getID().'/'); - - $form = new AphrontFormView(); - $form - ->setUser($viewer) - ->appendControl( - id(new AphrontFormTokenizerControl()) - ->setName('phids') - ->setLabel(pht('Add Members')) - ->setDatasource(new PhabricatorPeopleDatasource())) - ->appendChild( - id(new AphrontFormSubmitControl()) - ->addCancelButton($view_uri) - ->setValue(pht('Add Members'))); - $form_box = id(new PHUIObjectBoxView()) - ->setHeaderText($title) - ->setForm($form); - } - - $member_list = $this->renderMemberList($project, $handles); - - $nav = $this->getProfileMenu(); - $nav->selectFilter(PhabricatorProject::PANEL_MEMBERS); - - $crumbs = $this->buildApplicationCrumbs(); - $crumbs->addTextCrumb(pht('Members')); - - return $this->newPage() - ->setNavigation($nav) - ->setCrumbs($crumbs) - ->setTitle(array($project->getName(), $title)) - ->appendChild($form_box) - ->appendChild($member_list); - } - - private function renderMemberList( - PhabricatorProject $project, - array $handles) { - - $request = $this->getRequest(); - $viewer = $request->getUser(); - - $can_edit = PhabricatorPolicyFilter::hasCapability( - $viewer, - $project, - PhabricatorPolicyCapability::CAN_EDIT); - - $list = id(new PHUIObjectItemListView()) - ->setNoDataString(pht('This project does not have any members.')); - - foreach ($handles as $handle) { - $remove_uri = $this->getApplicationURI( - '/members/'.$project->getID().'/remove/?phid='.$handle->getPHID()); - - $item = id(new PHUIObjectItemView()) - ->setHeader($handle->getFullName()) - ->setHref($handle->getURI()) - ->setImageURI($handle->getImageURI()); - - if ($can_edit) { - $item->addAction( - id(new PHUIListItemView()) - ->setIcon('fa-times') - ->setName(pht('Remove')) - ->setHref($remove_uri) - ->setWorkflow(true)); - } - - $list->addItem($item); - } - - $box = id(new PHUIObjectBoxView()) - ->setHeaderText(pht('Members')) - ->setObjectList($list); - - return $box; - } -} diff --git a/src/applications/project/controller/PhabricatorProjectMembersRemoveController.php b/src/applications/project/controller/PhabricatorProjectMembersRemoveController.php index cad3f35c05..ea41ea7113 100644 --- a/src/applications/project/controller/PhabricatorProjectMembersRemoveController.php +++ b/src/applications/project/controller/PhabricatorProjectMembersRemoveController.php @@ -6,11 +6,13 @@ final class PhabricatorProjectMembersRemoveController public function handleRequest(AphrontRequest $request) { $viewer = $request->getViewer(); $id = $request->getURIData('id'); + $type = $request->getURIData('type'); $project = id(new PhabricatorProjectQuery()) ->setViewer($viewer) ->withIDs(array($id)) ->needMembers(true) + ->needWatchers(true) ->requireCapabilities( array( PhabricatorPolicyCapability::CAN_VIEW, @@ -21,27 +23,31 @@ final class PhabricatorProjectMembersRemoveController return new Aphront404Response(); } - $member_phids = $project->getMemberPHIDs(); - $remove_phid = $request->getStr('phid'); + if ($type == 'watchers') { + $is_watcher = true; + $edge_type = PhabricatorObjectHasWatcherEdgeType::EDGECONST; + } else { + if (!$project->supportsEditMembers()) { + return new Aphront404Response(); + } - if (!in_array($remove_phid, $member_phids)) { - return new Aphront404Response(); + $is_watcher = false; + $edge_type = PhabricatorProjectProjectHasMemberEdgeType::EDGECONST; } $members_uri = $this->getApplicationURI('members/'.$project->getID().'/'); + $remove_phid = $request->getStr('phid'); if ($request->isFormPost()) { - $member_spec = array(); - $member_spec['-'] = array($remove_phid => $remove_phid); - - $type_member = PhabricatorProjectProjectHasMemberEdgeType::EDGECONST; - $xactions = array(); $xactions[] = id(new PhabricatorProjectTransaction()) ->setTransactionType(PhabricatorTransactions::TYPE_EDGE) - ->setMetadataValue('edge:type', $type_member) - ->setNewValue($member_spec); + ->setMetadataValue('edge:type', $edge_type) + ->setNewValue( + array( + '-' => array($remove_phid => $remove_phid), + )); $editor = id(new PhabricatorProjectTransactionEditor($project)) ->setActor($viewer) @@ -59,18 +65,31 @@ final class PhabricatorProjectMembersRemoveController ->withPHIDs(array($remove_phid)) ->executeOne(); - $dialog = id(new AphrontDialogView()) - ->setUser($viewer) - ->setTitle(pht('Really Remove Member?')) - ->appendParagraph( - pht( - 'Really remove %s from the project %s?', - phutil_tag('strong', array(), $handle->getName()), - phutil_tag('strong', array(), $project->getName()))) - ->addCancelButton($members_uri) - ->addSubmitButton(pht('Remove Project Member')); + $target_name = phutil_tag('strong', array(), $handle->getName()); + $project_name = phutil_tag('strong', array(), $project->getName()); - return id(new AphrontDialogResponse())->setDialog($dialog); + if ($is_watcher) { + $title = pht('Remove Watcher'); + $body = pht( + 'Remove %s as a watcher of %s?', + $target_name, + $project_name); + $button = pht('Remove Watcher'); + } else { + $title = pht('Remove Member'); + $body = pht( + 'Remove %s as a project member of %s?', + $target_name, + $project_name); + $button = pht('Remove Member'); + } + + return $this->newDialog() + ->setTitle($title) + ->addHiddenInput('phid', $remove_phid) + ->appendParagraph($body) + ->addCancelButton($members_uri) + ->addSubmitButton($button); } } diff --git a/src/applications/project/controller/PhabricatorProjectMembersViewController.php b/src/applications/project/controller/PhabricatorProjectMembersViewController.php new file mode 100644 index 0000000000..efe2106a26 --- /dev/null +++ b/src/applications/project/controller/PhabricatorProjectMembersViewController.php @@ -0,0 +1,283 @@ +getViewer(); + $id = $request->getURIData('id'); + + $project = id(new PhabricatorProjectQuery()) + ->setViewer($viewer) + ->withIDs(array($id)) + ->needMembers(true) + ->needWatchers(true) + ->needImages(true) + ->executeOne(); + if (!$project) { + return new Aphront404Response(); + } + + $this->setProject($project); + $title = pht('Members and Watchers'); + + $properties = $this->buildProperties($project); + $actions = $this->buildActions($project); + $properties->setActionList($actions); + + $object_box = id(new PHUIObjectBoxView()) + ->setHeaderText($title) + ->addPropertyList($properties); + + $member_list = id(new PhabricatorProjectMemberListView()) + ->setUser($viewer) + ->setProject($project) + ->setUserPHIDs($project->getMemberPHIDs()); + + $watcher_list = id(new PhabricatorProjectWatcherListView()) + ->setUser($viewer) + ->setProject($project) + ->setUserPHIDs($project->getWatcherPHIDs()); + + $nav = $this->getProfileMenu(); + $nav->selectFilter(PhabricatorProject::PANEL_MEMBERS); + + $crumbs = $this->buildApplicationCrumbs(); + $crumbs->addTextCrumb(pht('Members')); + + return $this->newPage() + ->setNavigation($nav) + ->setCrumbs($crumbs) + ->setTitle(array($project->getName(), $title)) + ->appendChild( + array( + $object_box, + $member_list, + $watcher_list, + )); + } + + private function buildProperties(PhabricatorProject $project) { + $viewer = $this->getViewer(); + + $view = id(new PHUIPropertyListView()) + ->setUser($viewer) + ->setObject($project); + + if ($project->isMilestone()) { + $icon_key = PhabricatorProjectIconSet::getMilestoneIconKey(); + $icon = PhabricatorProjectIconSet::getIconIcon($icon_key); + $target = PhabricatorProjectIconSet::getIconName($icon_key); + $note = pht( + 'Members of the parent project are members of this project.'); + $show_join = false; + } else if ($project->getHasSubprojects()) { + $icon = 'fa-sitemap'; + $target = pht('Parent Project'); + $note = pht( + 'Members of all subprojects are members of this project.'); + $show_join = false; + } else if ($project->getIsMembershipLocked()) { + $icon = 'fa-lock'; + $target = pht('Locked Project'); + $note = pht( + 'Users with access may join this project, but may not leave.'); + $show_join = true; + } else { + $icon = 'fa-briefcase'; + $target = pht('Normal Project'); + $note = pht('Users with access may join and leave this project.'); + $show_join = true; + } + + $item = id(new PHUIStatusItemView()) + ->setIcon($icon) + ->setTarget(phutil_tag('strong', array(), $target)) + ->setNote($note); + + $status = id(new PHUIStatusListView()) + ->addItem($item); + + $view->addProperty(pht('Membership'), $status); + + if ($show_join) { + $descriptions = PhabricatorPolicyQuery::renderPolicyDescriptions( + $viewer, + $project); + + $view->addProperty( + pht('Joinable By'), + $descriptions[PhabricatorPolicyCapability::CAN_JOIN]); + } + + $viewer_phid = $viewer->getPHID(); + + if ($project->isUserWatcher($viewer_phid)) { + $watch_item = id(new PHUIStatusItemView()) + ->setIcon('fa-eye green') + ->setTarget(phutil_tag('strong', array(), pht('Watching'))) + ->setNote( + pht( + 'You will receive mail about changes made to any related '. + 'object.')); + + $watch_status = id(new PHUIStatusListView()) + ->addItem($watch_item); + + $view->addProperty(pht('Watching'), $watch_status); + } + + if ($project->isUserMember($viewer_phid)) { + $is_silenced = $this->isProjectSilenced($project); + if ($is_silenced) { + $mail_icon = 'fa-envelope-o grey'; + $mail_target = pht('Disabled'); + $mail_note = pht( + 'When mail is sent to project members, you will not receive '. + 'a copy.'); + } else { + $mail_icon = 'fa-envelope-o green'; + $mail_target = pht('Enabled'); + $mail_note = pht( + 'You will receive mail that is sent to project members.'); + } + + $mail_item = id(new PHUIStatusItemView()) + ->setIcon($mail_icon) + ->setTarget(phutil_tag('strong', array(), $mail_target)) + ->setNote($mail_note); + + $mail_status = id(new PHUIStatusListView()) + ->addItem($mail_item); + + $view->addProperty(pht('Mail to Members'), $mail_status); + } + + return $view; + } + + private function buildActions(PhabricatorProject $project) { + $viewer = $this->getViewer(); + $id = $project->getID(); + + $view = id(new PhabricatorActionListView()) + ->setUser($viewer); + + $is_locked = $project->getIsMembershipLocked(); + + $can_edit = PhabricatorPolicyFilter::hasCapability( + $viewer, + $project, + PhabricatorPolicyCapability::CAN_EDIT); + + $supports_edit = $project->supportsEditMembers(); + + $can_join = $supports_edit && PhabricatorPolicyFilter::hasCapability( + $viewer, + $project, + PhabricatorPolicyCapability::CAN_JOIN); + + $can_leave = $supports_edit && (!$is_locked || $can_edit); + + $viewer_phid = $viewer->getPHID(); + + if (!$project->isUserMember($viewer_phid)) { + $view->addAction( + id(new PhabricatorActionView()) + ->setHref('/project/update/'.$project->getID().'/join/') + ->setIcon('fa-plus') + ->setDisabled(!$can_join) + ->setWorkflow(true) + ->setName(pht('Join Project'))); + } else { + $view->addAction( + id(new PhabricatorActionView()) + ->setHref('/project/update/'.$project->getID().'/leave/') + ->setIcon('fa-times') + ->setDisabled(!$can_leave) + ->setWorkflow(true) + ->setName(pht('Leave Project'))); + } + + if (!$project->isUserWatcher($viewer->getPHID())) { + $view->addAction( + id(new PhabricatorActionView()) + ->setWorkflow(true) + ->setHref('/project/watch/'.$project->getID().'/') + ->setIcon('fa-eye') + ->setName(pht('Watch Project'))); + } else { + $view->addAction( + id(new PhabricatorActionView()) + ->setWorkflow(true) + ->setHref('/project/unwatch/'.$project->getID().'/') + ->setIcon('fa-eye-slash') + ->setName(pht('Unwatch Project'))); + } + + $can_silence = $project->isUserMember($viewer_phid); + $is_silenced = $this->isProjectSilenced($project); + + if ($is_silenced) { + $silence_text = pht('Enable Mail'); + } else { + $silence_text = pht('Disable Mail'); + } + + $view->addAction( + id(new PhabricatorActionView()) + ->setName($silence_text) + ->setIcon('fa-envelope-o') + ->setHref("/project/silence/{$id}/") + ->setWorkflow(true) + ->setDisabled(!$can_silence)); + + $can_add = $can_edit && $supports_edit; + + $view->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Add Members')) + ->setIcon('fa-user-plus') + ->setHref("/project/members/{$id}/add/") + ->setWorkflow(true) + ->setDisabled(!$can_add)); + + $can_lock = $can_edit && $supports_edit && $this->hasApplicationCapability( + ProjectCanLockProjectsCapability::CAPABILITY); + + if ($is_locked) { + $lock_name = pht('Unlock Project'); + $lock_icon = 'fa-unlock'; + } else { + $lock_name = pht('Lock Project'); + $lock_icon = 'fa-lock'; + } + + $view->addAction( + id(new PhabricatorActionView()) + ->setName($lock_name) + ->setIcon($lock_icon) + ->setHref($this->getApplicationURI("lock/{$id}/")) + ->setDisabled(!$can_lock) + ->setWorkflow(true)); + + return $view; + } + + private function isProjectSilenced(PhabricatorProject $project) { + $viewer = $this->getViewer(); + + $viewer_phid = $viewer->getPHID(); + if (!$viewer_phid) { + return false; + } + + $edge_type = PhabricatorProjectSilencedEdgeType::EDGECONST; + $silenced = PhabricatorEdgeQuery::loadDestinationPHIDs( + $project->getPHID(), + $edge_type); + $silenced = array_fuse($silenced); + return isset($silenced[$viewer_phid]); + } + +} diff --git a/src/applications/project/controller/PhabricatorProjectPanelController.php b/src/applications/project/controller/PhabricatorProjectPanelController.php index 02b16dcfb4..d20b5b9828 100644 --- a/src/applications/project/controller/PhabricatorProjectPanelController.php +++ b/src/applications/project/controller/PhabricatorProjectPanelController.php @@ -12,10 +12,13 @@ final class PhabricatorProjectPanelController $viewer = $this->getViewer(); $project = $this->getProject(); - return id(new PhabricatorProfilePanelEngine()) + $engine = id(new PhabricatorProjectProfilePanelEngine()) ->setProfileObject($project) - ->setController($this) - ->buildResponse(); + ->setController($this); + + $this->setProfilePanelEngine($engine); + + return $engine->buildResponse(); } } diff --git a/src/applications/project/controller/PhabricatorProjectProfileController.php b/src/applications/project/controller/PhabricatorProjectProfileController.php index a2eb5eebe6..721193c469 100644 --- a/src/applications/project/controller/PhabricatorProjectProfileController.php +++ b/src/applications/project/controller/PhabricatorProjectProfileController.php @@ -8,13 +8,12 @@ final class PhabricatorProjectProfileController } public function handleRequest(AphrontRequest $request) { - $viewer = $request->getUser(); - $response = $this->loadProject(); if ($response) { return $response; } + $viewer = $request->getUser(); $project = $this->getProject(); $id = $project->getID(); $picture = $project->getProfileImageURI(); @@ -38,14 +37,52 @@ final class PhabricatorProjectProfileController ->setHeader($header) ->addPropertyList($properties); - $timeline = $this->buildTransactionTimeline( - $project, - new PhabricatorProjectTransactionQuery()); - $timeline->setShouldTerminate(true); + $member_list = id(new PhabricatorProjectMemberListView()) + ->setUser($viewer) + ->setProject($project) + ->setLimit(5) + ->setUserPHIDs($project->getMemberPHIDs()); + + $watcher_list = id(new PhabricatorProjectWatcherListView()) + ->setUser($viewer) + ->setProject($project) + ->setLimit(5) + ->setUserPHIDs($project->getWatcherPHIDs()); $nav = $this->getProfileMenu(); $nav->selectFilter(PhabricatorProject::PANEL_PROFILE); + $watch_action = $this->renderWatchAction($project); + + $stories = id(new PhabricatorFeedQuery()) + ->setViewer($viewer) + ->setFilterPHIDs( + array( + $project->getPHID(), + )) + ->setLimit(50) + ->execute(); + + + $feed = $this->renderStories($stories); + + $feed_header = id(new PHUIHeaderView()) + ->setHeader(pht('Recent Activity')) + ->addActionLink($watch_action); + + $feed = id(new PHUIObjectBoxView()) + ->setHeader($feed_header) + ->appendChild($feed); + + $columns = id(new AphrontMultiColumnView()) + ->setFluidLayout(true) + ->addColumn($feed) + ->addColumn( + array( + $member_list, + $watcher_list, + )); + $crumbs = $this->buildApplicationCrumbs(); return $this->newPage() @@ -53,8 +90,11 @@ final class PhabricatorProjectProfileController ->setCrumbs($crumbs) ->setTitle($project->getName()) ->setPageObjectPHIDs(array($project->getPHID())) - ->appendChild($object_box) - ->appendChild($timeline); + ->appendChild( + array( + $object_box, + $columns, + )); } private function buildActionListView(PhabricatorProject $project) { @@ -67,103 +107,11 @@ final class PhabricatorProjectProfileController ->setUser($viewer) ->setObject($project); - $can_edit = PhabricatorPolicyFilter::hasCapability( - $viewer, - $project, - PhabricatorPolicyCapability::CAN_EDIT); - $view->addAction( id(new PhabricatorActionView()) - ->setName(pht('Edit Details')) + ->setName(pht('Edit Project')) ->setIcon('fa-pencil') - ->setHref($this->getApplicationURI("edit/{$id}/")) - ->setDisabled(!$can_edit) - ->setWorkflow(!$can_edit)); - - $view->addAction( - id(new PhabricatorActionView()) - ->setName(pht('Edit Picture')) - ->setIcon('fa-picture-o') - ->setHref($this->getApplicationURI("picture/{$id}/")) - ->setDisabled(!$can_edit) - ->setWorkflow(!$can_edit)); - - if ($project->isArchived()) { - $view->addAction( - id(new PhabricatorActionView()) - ->setName(pht('Activate Project')) - ->setIcon('fa-check') - ->setHref($this->getApplicationURI("archive/{$id}/")) - ->setDisabled(!$can_edit) - ->setWorkflow(true)); - } else { - $view->addAction( - id(new PhabricatorActionView()) - ->setName(pht('Archive Project')) - ->setIcon('fa-ban') - ->setHref($this->getApplicationURI("archive/{$id}/")) - ->setDisabled(!$can_edit) - ->setWorkflow(true)); - } - - $can_lock = $can_edit && $this->hasApplicationCapability( - ProjectCanLockProjectsCapability::CAPABILITY); - - if ($project->getIsMembershipLocked()) { - $lock_name = pht('Unlock Project'); - $lock_icon = 'fa-unlock'; - } else { - $lock_name = pht('Lock Project'); - $lock_icon = 'fa-lock'; - } - - $view->addAction( - id(new PhabricatorActionView()) - ->setName($lock_name) - ->setIcon($lock_icon) - ->setHref($this->getApplicationURI("lock/{$id}/")) - ->setDisabled(!$can_lock) - ->setWorkflow(true)); - - $action = null; - if (!$project->isUserMember($viewer->getPHID())) { - $can_join = PhabricatorPolicyFilter::hasCapability( - $viewer, - $project, - PhabricatorPolicyCapability::CAN_JOIN); - - $action = id(new PhabricatorActionView()) - ->setUser($viewer) - ->setRenderAsForm(true) - ->setHref('/project/update/'.$project->getID().'/join/') - ->setIcon('fa-plus') - ->setDisabled(!$can_join) - ->setName(pht('Join Project')); - $view->addAction($action); - } else { - $action = id(new PhabricatorActionView()) - ->setWorkflow(true) - ->setHref('/project/update/'.$project->getID().'/leave/') - ->setIcon('fa-times') - ->setName(pht('Leave Project...')); - $view->addAction($action); - - if (!$project->isUserWatcher($viewer->getPHID())) { - $action = id(new PhabricatorActionView()) - ->setWorkflow(true) - ->setHref('/project/watch/'.$project->getID().'/') - ->setIcon('fa-eye') - ->setName(pht('Watch Project')); - $view->addAction($action); - } else { - $action = id(new PhabricatorActionView()) - ->setWorkflow(true) - ->setHref('/project/unwatch/'.$project->getID().'/') - ->setIcon('fa-eye-slash') - ->setName(pht('Unwatch Project')); - $view->addAction($action); - } - } + ->setHref($this->getApplicationURI("history/{$id}/"))); return $view; } @@ -179,45 +127,10 @@ final class PhabricatorProjectProfileController ->setObject($project) ->setActionList($actions); - $hashtags = array(); - foreach ($project->getSlugs() as $slug) { - $hashtags[] = id(new PHUITagView()) - ->setType(PHUITagView::TYPE_OBJECT) - ->setName('#'.$slug->getSlug()); - } - - if ($hashtags) { - $view->addProperty(pht('Hashtags'), phutil_implode_html(' ', $hashtags)); - } - - $view->addProperty( - pht('Members'), - $project->getMemberPHIDs() - ? $viewer - ->renderHandleList($project->getMemberPHIDs()) - ->setAsInline(true) - : phutil_tag('em', array(), pht('None'))); - - $view->addProperty( - pht('Watchers'), - $project->getWatcherPHIDs() - ? $viewer - ->renderHandleList($project->getWatcherPHIDs()) - ->setAsInline(true) - : phutil_tag('em', array(), pht('None'))); - - $descriptions = PhabricatorPolicyQuery::renderPolicyDescriptions( - $viewer, - $project); - $view->addProperty( pht('Looks Like'), $viewer->renderHandle($project->getPHID())->setAsTag(true)); - $view->addProperty( - pht('Joinable By'), - $descriptions[PhabricatorPolicyCapability::CAN_JOIN]); - $field_list = PhabricatorCustomField::getObjectFields( $project, PhabricatorCustomField::ROLE_VIEW); @@ -226,5 +139,44 @@ final class PhabricatorProjectProfileController return $view; } + private function renderStories(array $stories) { + assert_instances_of($stories, 'PhabricatorFeedStory'); + + $builder = new PhabricatorFeedBuilder($stories); + $builder->setUser($this->getRequest()->getUser()); + $builder->setShowHovercards(true); + $view = $builder->buildView(); + + return phutil_tag_div('profile-feed', $view->render()); + } + + private function renderWatchAction(PhabricatorProject $project) { + $viewer = $this->getViewer(); + $viewer_phid = $viewer->getPHID(); + $id = $project->getID(); + + $is_watcher = ($viewer_phid && $project->isUserWatcher($viewer_phid)); + + if (!$is_watcher) { + $watch_icon = 'fa-eye'; + $watch_text = pht('Watch Project'); + $watch_href = "/project/watch/{$id}/?via=profile"; + } else { + $watch_icon = 'fa-eye-slash'; + $watch_text = pht('Unwatch Project'); + $watch_href = "/project/unwatch/{$id}/?via=profile"; + } + + $watch_icon = id(new PHUIIconView()) + ->setIconFont($watch_icon); + + return id(new PHUIButtonView()) + ->setTag('a') + ->setWorkflow(true) + ->setIcon($watch_icon) + ->setText($watch_text) + ->setHref($watch_href); + } + } diff --git a/src/applications/project/controller/PhabricatorProjectSilenceController.php b/src/applications/project/controller/PhabricatorProjectSilenceController.php new file mode 100644 index 0000000000..6edd9bab39 --- /dev/null +++ b/src/applications/project/controller/PhabricatorProjectSilenceController.php @@ -0,0 +1,87 @@ +getViewer(); + $id = $request->getURIData('id'); + $action = $request->getURIData('action'); + + $project = id(new PhabricatorProjectQuery()) + ->setViewer($viewer) + ->withIDs(array($id)) + ->needMembers(true) + ->executeOne(); + if (!$project) { + return new Aphront404Response(); + } + + $edge_type = PhabricatorProjectSilencedEdgeType::EDGECONST; + $done_uri = "/project/members/{$id}/"; + $viewer_phid = $viewer->getPHID(); + + if (!$project->isUserMember($viewer_phid)) { + return $this->newDialog() + ->setTitle(pht('Not a Member')) + ->appendParagraph( + pht( + 'You are not a project member, so you do not receive mail sent '. + 'to members of this project.')) + ->addCancelButton($done_uri); + } + + $silenced = PhabricatorEdgeQuery::loadDestinationPHIDs( + $project->getPHID(), + $edge_type); + $silenced = array_fuse($silenced); + $is_silenced = isset($silenced[$viewer_phid]); + + if ($request->isDialogFormPost()) { + if ($is_silenced) { + $edge_action = '-'; + } else { + $edge_action = '+'; + } + + $xactions = array(); + $xactions[] = id(new PhabricatorProjectTransaction()) + ->setTransactionType(PhabricatorTransactions::TYPE_EDGE) + ->setMetadataValue('edge:type', $edge_type) + ->setNewValue( + array( + $edge_action => array($viewer_phid => $viewer_phid), + )); + + $editor = id(new PhabricatorProjectTransactionEditor($project)) + ->setActor($viewer) + ->setContentSourceFromRequest($request) + ->setContinueOnNoEffect(true) + ->setContinueOnMissingFields(true) + ->applyTransactions($project, $xactions); + + return id(new AphrontRedirectResponse())->setURI($done_uri); + } + + if ($is_silenced) { + $title = pht('Enable Mail'); + $body = pht( + 'When mail is sent to members of this project, you will receive a '. + 'copy.'); + $button = pht('Enable Project Mail'); + } else { + $title = pht('Disable Mail'); + $body = pht( + 'When mail is sent to members of this project, you will no longer '. + 'receive a copy.'); + $button = pht('Disable Project Mail'); + } + + return $this->newDialog() + ->setTitle($title) + ->appendParagraph($body) + ->addCancelButton($done_uri) + ->addSubmitButton($button); + } + +} diff --git a/src/applications/project/controller/PhabricatorProjectUpdateController.php b/src/applications/project/controller/PhabricatorProjectUpdateController.php index cfdeb4fd09..762343f485 100644 --- a/src/applications/project/controller/PhabricatorProjectUpdateController.php +++ b/src/applications/project/controller/PhabricatorProjectUpdateController.php @@ -12,14 +12,11 @@ final class PhabricatorProjectUpdateController PhabricatorPolicyCapability::CAN_VIEW, ); - $process_action = false; switch ($action) { case 'join': $capabilities[] = PhabricatorPolicyCapability::CAN_JOIN; - $process_action = $request->isFormPost(); break; case 'leave': - $process_action = $request->isDialogFormPost(); break; default: return new Aphront404Response(); @@ -35,10 +32,13 @@ final class PhabricatorProjectUpdateController return new Aphront404Response(); } - $project_uri = $this->getApplicationURI('profile/'.$project->getID().'/'); + if (!$project->supportsEditMembers()) { + return new Aphront404Response(); + } - if ($process_action) { + $done_uri = "/project/members/{$id}/"; + if ($request->isFormPost()) { $edge_action = null; switch ($action) { case 'join': @@ -50,6 +50,7 @@ final class PhabricatorProjectUpdateController } $type_member = PhabricatorProjectProjectHasMemberEdgeType::EDGECONST; + $member_spec = array( $edge_action => array($viewer->getPHID() => $viewer->getPHID()), ); @@ -67,46 +68,47 @@ final class PhabricatorProjectUpdateController ->setContinueOnMissingFields(true) ->applyTransactions($project, $xactions); - return id(new AphrontRedirectResponse())->setURI($project_uri); + return id(new AphrontRedirectResponse())->setURI($done_uri); } - $dialog = null; - switch ($action) { - case 'leave': - $dialog = new AphrontDialogView(); - $dialog->setUser($viewer); - if ($this->userCannotLeave($project)) { - $dialog->setTitle(pht('You can not leave this project.')); - $body = pht('The membership is locked for this project.'); - } else { - $dialog->setTitle(pht('Really leave project?')); - $body = pht( - 'Your tremendous contributions to this project will be sorely '. - 'missed. Are you sure you want to leave?'); - $dialog->addSubmitButton(pht('Leave Project')); - } - $dialog->appendParagraph($body); - $dialog->addCancelButton($project_uri); - break; - default: - return new Aphront404Response(); + $is_locked = $project->getIsMembershipLocked(); + $can_edit = PhabricatorPolicyFilter::hasCapability( + $viewer, + $project, + PhabricatorPolicyCapability::CAN_EDIT); + $can_leave = ($can_edit || !$is_locked); + + $button = null; + if ($action == 'leave') { + if ($can_leave) { + $title = pht('Leave Project'); + $body = pht( + 'Your tremendous contributions to this project will be sorely '. + 'missed. Are you sure you want to leave?'); + $button = pht('Leave Project'); + } else { + $title = pht('Membership Locked'); + $body = pht( + 'Membership for this project is locked. You can not leave.'); + } + } else { + $title = pht('Join Project'); + $body = pht( + 'Join this project? You will become a member and enjoy whatever '. + 'benefits membership may confer.'); + $button = pht('Join Project'); } - return id(new AphrontDialogResponse())->setDialog($dialog); + $dialog = $this->newDialog() + ->setTitle($title) + ->appendParagraph($body) + ->addCancelButton($done_uri); + + if ($button) { + $dialog->addSubmitButton($button); + } + + return $dialog; } - /** - * This is enforced in @{class:PhabricatorProjectTransactionEditor}. We use - * this logic to render a better form for users hitting this case. - */ - private function userCannotLeave(PhabricatorProject $project) { - $viewer = $this->getViewer(); - - return - $project->getIsMembershipLocked() && - !PhabricatorPolicyFilter::hasCapability( - $viewer, - $project, - PhabricatorPolicyCapability::CAN_EDIT); - } } diff --git a/src/applications/project/controller/PhabricatorProjectViewController.php b/src/applications/project/controller/PhabricatorProjectViewController.php index 087971878b..412565c056 100644 --- a/src/applications/project/controller/PhabricatorProjectViewController.php +++ b/src/applications/project/controller/PhabricatorProjectViewController.php @@ -17,21 +17,14 @@ final class PhabricatorProjectViewController } $project = $this->getProject(); - $columns = id(new PhabricatorProjectColumnQuery()) - ->setViewer($viewer) - ->withProjectPHIDs(array($project->getPHID())) - ->execute(); - if ($columns) { - $controller = 'board'; - } else { - $controller = 'profile'; - } + $engine = $this->getProfilePanelEngine(); + $default = $engine->getDefaultPanel(); - switch ($controller) { - case 'board': + switch ($default->getBuiltinKey()) { + case PhabricatorProject::PANEL_WORKBOARD: $controller_object = new PhabricatorProjectBoardViewController(); break; - case 'profile': + case PhabricatorProject::PANEL_PROFILE: default: $controller_object = new PhabricatorProjectProfileController(); break; diff --git a/src/applications/project/controller/PhabricatorProjectWatchController.php b/src/applications/project/controller/PhabricatorProjectWatchController.php index 53538f8393..9624a0b730 100644 --- a/src/applications/project/controller/PhabricatorProjectWatchController.php +++ b/src/applications/project/controller/PhabricatorProjectWatchController.php @@ -18,11 +18,11 @@ final class PhabricatorProjectWatchController return new Aphront404Response(); } - $project_uri = $this->getApplicationURI('profile/'.$project->getID().'/'); - - // You must be a member of a project to - if (!$project->isUserMember($viewer->getPHID())) { - return new Aphront400Response(); + $via = $request->getStr('via'); + if ($via == 'profile') { + $done_uri = "/project/profile/{$id}/"; + } else { + $done_uri = "/project/members/{$id}/"; } if ($request->isDialogFormPost()) { @@ -30,15 +30,13 @@ final class PhabricatorProjectWatchController switch ($action) { case 'watch': $edge_action = '+'; - $force_subscribe = true; break; case 'unwatch': $edge_action = '-'; - $force_subscribe = false; break; } - $type_member = PhabricatorObjectHasWatcherEdgeType::EDGECONST; + $type_watcher = PhabricatorObjectHasWatcherEdgeType::EDGECONST; $member_spec = array( $edge_action => array($viewer->getPHID() => $viewer->getPHID()), ); @@ -46,7 +44,7 @@ final class PhabricatorProjectWatchController $xactions = array(); $xactions[] = id(new PhabricatorProjectTransaction()) ->setTransactionType(PhabricatorTransactions::TYPE_EDGE) - ->setMetadataValue('edge:type', $type_member) + ->setMetadataValue('edge:type', $type_watcher) ->setNewValue($member_spec); $editor = id(new PhabricatorProjectTransactionEditor($project)) @@ -56,7 +54,7 @@ final class PhabricatorProjectWatchController ->setContinueOnMissingFields(true) ->applyTransactions($project, $xactions); - return id(new AphrontRedirectResponse())->setURI($project_uri); + return id(new AphrontRedirectResponse())->setURI($done_uri); } $dialog = null; @@ -82,8 +80,9 @@ final class PhabricatorProjectWatchController return $this->newDialog() ->setTitle($title) + ->addHiddenInput('via', $via) ->appendParagraph($body) - ->addCancelButton($project_uri) + ->addCancelButton($done_uri) ->addSubmitButton($submit); } diff --git a/src/applications/project/edge/PhabricatorProjectSilencedEdgeType.php b/src/applications/project/edge/PhabricatorProjectSilencedEdgeType.php new file mode 100644 index 0000000000..1fbc1a9ab7 --- /dev/null +++ b/src/applications/project/edge/PhabricatorProjectSilencedEdgeType.php @@ -0,0 +1,8 @@ +getTransactionType()) { - case PhabricatorTransactions::TYPE_EDGE: - $edge_type = $xaction->getMetadataValue('edge:type'); - switch ($edge_type) { - case PhabricatorProjectProjectHasMemberEdgeType::EDGECONST: - case PhabricatorObjectHasWatcherEdgeType::EDGECONST: - $old = $xaction->getOldValue(); - $new = $xaction->getNewValue(); - - // When adding members or watchers, we add subscriptions. - $add = array_keys(array_diff_key($new, $old)); - - // When removing members, we remove their subscription too. - // When unwatching, we leave subscriptions, since it's fine to be - // subscribed to a project but not be a member of it. - $edge_const = PhabricatorProjectProjectHasMemberEdgeType::EDGECONST; - if ($edge_type == $edge_const) { - $rem = array_keys(array_diff_key($old, $new)); - } else { - $rem = array(); - } - - // NOTE: The subscribe is "explicit" because there's no implicit - // unsubscribe, so Join -> Leave -> Join doesn't resubscribe you - // if we use an implicit subscribe, even though you never willfully - // unsubscribed. Not sure if adding implicit unsubscribe (which - // would not write the unsubscribe row) is justified to deal with - // this, which is a fairly weird edge case and pretty arguable both - // ways. - - // Subscriptions caused by watches should also clearly be explicit, - // and that case is unambiguous. - - id(new PhabricatorSubscriptionsEditor()) - ->setActor($this->requireActor()) - ->setObject($object) - ->subscribeExplicit($add) - ->unsubscribe($rem) - ->save(); - - if ($rem) { - // When removing members, also remove any watches on the project. - $edge_editor = new PhabricatorEdgeEditor(); - foreach ($rem as $rem_phid) { - $edge_editor->removeEdge( - $object->getPHID(), - PhabricatorObjectHasWatcherEdgeType::EDGECONST, - $rem_phid); - } - $edge_editor->save(); - } - break; - } - break; - } - - return parent::applyBuiltinExternalTransaction($object, $xaction); - } - protected function validateAllTransactions( PhabricatorLiskDAO $object, array $xactions) { @@ -582,7 +519,7 @@ final class PhabricatorProjectTransactionEditor return id(new PhabricatorProjectQuery()) ->setViewer(PhabricatorUser::getOmnipotentUser()) ->withPHIDs(array($object->getPHID())) - ->needMembers(true) + ->needAncestorMembers(true) ->executeOne(); } @@ -602,6 +539,10 @@ final class PhabricatorProjectTransactionEditor ); } + protected function getMailCc(PhabricatorLiskDAO $object) { + return array(); + } + public function getMailTagsMap() { return array( PhabricatorProjectTransaction::MAILTAG_METADATA => @@ -610,8 +551,6 @@ final class PhabricatorProjectTransactionEditor pht('Project membership changes.'), PhabricatorProjectTransaction::MAILTAG_WATCHERS => pht('Project watcher list changes.'), - PhabricatorProjectTransaction::MAILTAG_SUBSCRIBERS => - pht('Project subscribers change.'), PhabricatorProjectTransaction::MAILTAG_OTHER => pht('Other project activity not listed above occurs.'), ); @@ -713,6 +652,10 @@ final class PhabricatorProjectTransactionEditor } } + if ($this->getIsNewObject()) { + $this->setDefaultProfilePicture($object); + } + // TODO: We should dump an informational transaction onto the parent // project to show that we created the sub-thing. @@ -756,12 +699,17 @@ final class PhabricatorProjectTransactionEditor } private function removeSlugs(PhabricatorProject $project, array $slugs) { - $slugs = $this->normalizeSlugs($slugs); - if (!$slugs) { return; } + // We're going to try to delete both the literal and normalized versions + // of all slugs. This allows us to destroy old slugs that are no longer + // valid. + foreach ($this->normalizeSlugs($slugs) as $slug) { + $slugs[] = $slug; + } + $objects = id(new PhabricatorProjectSlug())->loadAllWhere( 'projectPHID = %s AND slug IN (%Ls)', $project->getPHID(), @@ -881,5 +829,46 @@ final class PhabricatorProjectTransactionEditor return $results; } + private function setDefaultProfilePicture(PhabricatorProject $project) { + if ($project->isMilestone()) { + return; + } + + $compose_color = $project->getDisplayIconComposeColor(); + $compose_icon = $project->getDisplayIconComposeIcon(); + + $builtin = id(new PhabricatorFilesComposeIconBuiltinFile()) + ->setColor($compose_color) + ->setIcon($compose_icon); + + $data = $builtin->loadBuiltinFileData(); + + $file = PhabricatorFile::newFromFileData( + $data, + array( + 'name' => $builtin->getBuiltinDisplayName(), + 'profile' => true, + 'canCDN' => true, + )); + + $project + ->setProfileImagePHID($file->getPHID()) + ->save(); + } + + + protected function shouldApplyHeraldRules( + PhabricatorLiskDAO $object, + array $xactions) { + return true; + } + + protected function buildHeraldAdapter( + PhabricatorLiskDAO $object, + array $xactions) { + + return id(new PhabricatorProjectHeraldAdapter()) + ->setProject($object); + } } diff --git a/src/applications/project/engine/PhabricatorProjectEditEngine.php b/src/applications/project/engine/PhabricatorProjectEditEngine.php index 389c585fce..c9861e96a6 100644 --- a/src/applications/project/engine/PhabricatorProjectEditEngine.php +++ b/src/applications/project/engine/PhabricatorProjectEditEngine.php @@ -78,7 +78,12 @@ final class PhabricatorProjectEditEngine } protected function getObjectViewURI($object) { - return $object->getURI(); + if ($this->getIsCreate()) { + return $object->getURI(); + } else { + $id = $object->getID(); + return "/project/history/{$id}/"; + } } protected function getObjectCreateCancelURI($object) { @@ -143,7 +148,6 @@ final class PhabricatorProjectEditEngine 'icon', 'color', 'slugs', - 'subscriberPHIDs', )); return array( diff --git a/src/applications/project/engine/PhabricatorProjectProfilePanelEngine.php b/src/applications/project/engine/PhabricatorProjectProfilePanelEngine.php new file mode 100644 index 0000000000..d37178ef7a --- /dev/null +++ b/src/applications/project/engine/PhabricatorProjectProfilePanelEngine.php @@ -0,0 +1,30 @@ +getProfileObject(); + $id = $project->getID(); + return "/project/{$id}/panel/{$path}"; + } + + protected function getBuiltinProfilePanels($object) { + $panels = array(); + + $panels[] = $this->newPanel() + ->setBuiltinKey(PhabricatorProject::PANEL_PROFILE) + ->setPanelKey(PhabricatorProjectDetailsProfilePanel::PANELKEY); + + $panels[] = $this->newPanel() + ->setBuiltinKey(PhabricatorProject::PANEL_WORKBOARD) + ->setPanelKey(PhabricatorProjectWorkboardProfilePanel::PANELKEY); + + $panels[] = $this->newPanel() + ->setBuiltinKey(PhabricatorProject::PANEL_MEMBERS) + ->setPanelKey(PhabricatorProjectMembersProfilePanel::PANELKEY); + + return $panels; + } + +} diff --git a/src/applications/project/herald/HeraldExactProjectsField.php b/src/applications/project/herald/HeraldExactProjectsField.php new file mode 100644 index 0000000000..73f91e36dc --- /dev/null +++ b/src/applications/project/herald/HeraldExactProjectsField.php @@ -0,0 +1,31 @@ +getPHID()); + } + + protected function getHeraldFieldStandardType() { + return self::STANDARD_PHID_LIST; + } + + protected function getDatasource() { + return new PhabricatorProjectDatasource(); + } + +} diff --git a/src/applications/project/herald/PhabricatorProjectHeraldAdapter.php b/src/applications/project/herald/PhabricatorProjectHeraldAdapter.php new file mode 100644 index 0000000000..f6d0984cb6 --- /dev/null +++ b/src/applications/project/herald/PhabricatorProjectHeraldAdapter.php @@ -0,0 +1,66 @@ +project = $this->newObject(); + } + + public function supportsApplicationEmail() { + return true; + } + + public function getRepetitionOptions() { + return array( + HeraldRepetitionPolicyConfig::EVERY, + HeraldRepetitionPolicyConfig::FIRST, + ); + } + + public function supportsRuleType($rule_type) { + switch ($rule_type) { + case HeraldRuleTypeConfig::RULE_TYPE_GLOBAL: + case HeraldRuleTypeConfig::RULE_TYPE_PERSONAL: + return true; + case HeraldRuleTypeConfig::RULE_TYPE_OBJECT: + default: + return false; + } + } + + public function setProject(PhabricatorProject $project) { + $this->project = $project; + return $this; + } + + public function getProject() { + return $this->project; + } + + public function getObject() { + return $this->project; + } + + public function getAdapterContentName() { + return pht('Projects'); + } + + public function getHeraldName() { + return pht('Project %s', $this->getProject()->getName()); + } + +} diff --git a/src/applications/project/herald/PhabricatorProjectHeraldFieldGroup.php b/src/applications/project/herald/PhabricatorProjectHeraldFieldGroup.php new file mode 100644 index 0000000000..ba219f64b5 --- /dev/null +++ b/src/applications/project/herald/PhabricatorProjectHeraldFieldGroup.php @@ -0,0 +1,15 @@ + PHUITagView::COLOR_RED, + 'name' => pht('Red'), + ), + array( + 'key' => PHUITagView::COLOR_ORANGE, + 'name' => pht('Orange'), + ), + array( + 'key' => PHUITagView::COLOR_YELLOW, + 'name' => pht('Yellow'), + ), + array( + 'key' => PHUITagView::COLOR_GREEN, + 'name' => pht('Green'), + ), + array( + 'key' => PHUITagView::COLOR_BLUE, + 'name' => pht('Blue'), + 'default' => true, + ), + array( + 'key' => PHUITagView::COLOR_INDIGO, + 'name' => pht('Indigo'), + ), + array( + 'key' => PHUITagView::COLOR_VIOLET, + 'name' => pht('Violet'), + ), + array( + 'key' => PHUITagView::COLOR_PINK, + 'name' => pht('Pink'), + ), + array( + 'key' => PHUITagView::COLOR_GREY, + 'name' => pht('Grey'), + ), + array( + 'key' => PHUITagView::COLOR_CHECKERED, + 'name' => pht('Checkered'), + ), + ); + } + + public static function validateColorConfiguration($config) { + if (!is_array($config)) { + throw new Exception( + pht('Configuration must be a list of project color specifications.')); + } + + $available_keys = self::getAvailableColorKeys(); + $available_keys = array_fuse($available_keys); + + foreach ($config as $idx => $value) { + if (!is_array($value)) { + throw new Exception( + pht( + 'Value for index "%s" should be a dictionary.', + $idx)); + } + + PhutilTypeSpec::checkMap( + $value, + array( + 'key' => 'string', + 'name' => 'string', + 'default' => 'optional bool', + )); + + $key = $value['key']; + if (!isset($available_keys[$key])) { + throw new Exception( + pht( + 'Color key "%s" is not a valid color key. The supported color '. + 'keys are: %s.', + $key, + implode(', ', $available_keys))); + } + } + + $default = null; + $keys = array(); + foreach ($config as $idx => $value) { + $key = $value['key']; + if (isset($keys[$key])) { + throw new Exception( + pht( + 'Project colors must have unique keys, but two icons share the '. + 'same key ("%s").', + $key)); + } else { + $keys[$key] = true; + } + + if (idx($value, 'default')) { + if ($default === null) { + $default = $value; + } else { + $original_key = $default['key']; + throw new Exception( + pht( + 'Two different colors ("%s", "%s") are marked as the default '. + 'color. Only one color may be marked as the default.', + $key, + $original_key)); + } + } + } + + if ($default === null) { + throw new Exception( + pht( + 'Project colors must include one color marked as the "%s" color, '. + 'but no such color exists.', + 'default')); + } + + } + } diff --git a/src/applications/project/profilepanel/PhabricatorProjectDetailsProfilePanel.php b/src/applications/project/profilepanel/PhabricatorProjectDetailsProfilePanel.php index 5a8bacf9dd..07e6ce4c10 100644 --- a/src/applications/project/profilepanel/PhabricatorProjectDetailsProfilePanel.php +++ b/src/applications/project/profilepanel/PhabricatorProjectDetailsProfilePanel.php @@ -13,6 +13,11 @@ final class PhabricatorProjectDetailsProfilePanel return pht('Project Details'); } + public function canMakeDefault( + PhabricatorProfilePanelConfiguration $config) { + return true; + } + public function getDisplayName( PhabricatorProfilePanelConfiguration $config) { $name = $config->getPanelProperty('name'); @@ -46,9 +51,7 @@ final class PhabricatorProjectDetailsProfilePanel $href = "/project/profile/{$id}/"; - $item = id(new PHUIListItemView()) - ->setRenderNameAsTooltip(true) - ->setType(PHUIListItemView::TYPE_ICON_NAV) + $item = $this->newItem() ->setHref($href) ->setName($name) ->setProfileImage($picture); diff --git a/src/applications/project/profilepanel/PhabricatorProjectMembersProfilePanel.php b/src/applications/project/profilepanel/PhabricatorProjectMembersProfilePanel.php index 0db2a03773..b5374416aa 100644 --- a/src/applications/project/profilepanel/PhabricatorProjectMembersProfilePanel.php +++ b/src/applications/project/profilepanel/PhabricatorProjectMembersProfilePanel.php @@ -46,9 +46,7 @@ final class PhabricatorProjectMembersProfilePanel $icon = 'fa-group'; $href = "/project/members/{$id}/"; - $item = id(new PHUIListItemView()) - ->setRenderNameAsTooltip(true) - ->setType(PHUIListItemView::TYPE_ICON_NAV) + $item = $this->newItem() ->setHref($href) ->setName($name) ->setIcon($icon); diff --git a/src/applications/project/profilepanel/PhabricatorProjectWorkboardProfilePanel.php b/src/applications/project/profilepanel/PhabricatorProjectWorkboardProfilePanel.php index 91f2f553f5..9bf28cdb31 100644 --- a/src/applications/project/profilepanel/PhabricatorProjectWorkboardProfilePanel.php +++ b/src/applications/project/profilepanel/PhabricatorProjectWorkboardProfilePanel.php @@ -13,6 +13,11 @@ final class PhabricatorProjectWorkboardProfilePanel return pht('Workboard'); } + public function canMakeDefault( + PhabricatorProfilePanelConfiguration $config) { + return true; + } + public function getDisplayName( PhabricatorProfilePanelConfiguration $config) { $name = $config->getPanelProperty('name'); @@ -47,26 +52,17 @@ final class PhabricatorProjectWorkboardProfilePanel $project = $config->getProfileObject(); - $columns = id(new PhabricatorProjectColumnQuery()) - ->setViewer($viewer) - ->withProjectPHIDs(array($project->getPHID())) - ->execute(); - if ($columns) { - $icon = 'fa-columns'; - } else { - $icon = 'fa-columns grey'; - } + $has_workboard = $project->getHasWorkboard(); $id = $project->getID(); $href = "/project/board/{$id}/"; $name = $this->getDisplayName($config); - $item = id(new PHUIListItemView()) - ->setRenderNameAsTooltip(true) - ->setType(PHUIListItemView::TYPE_ICON_NAV) + $item = $this->newItem() ->setHref($href) ->setName($name) - ->setIcon($icon); + ->setDisabled(!$has_workboard) + ->setIcon('fa-columns'); return array( $item, diff --git a/src/applications/project/query/PhabricatorProjectQuery.php b/src/applications/project/query/PhabricatorProjectQuery.php index bc14e93a88..304dd956e1 100644 --- a/src/applications/project/query/PhabricatorProjectQuery.php +++ b/src/applications/project/query/PhabricatorProjectQuery.php @@ -9,6 +9,7 @@ final class PhabricatorProjectQuery private $slugs; private $slugNormals; private $slugMap; + private $allSlugs; private $names; private $nameTokens; private $icons; @@ -29,6 +30,7 @@ final class PhabricatorProjectQuery private $needSlugs; private $needMembers; + private $needAncestorMembers; private $needWatchers; private $needImages; @@ -108,6 +110,11 @@ final class PhabricatorProjectQuery return $this; } + public function needAncestorMembers($need_ancestor_members) { + $this->needAncestorMembers = $need_ancestor_members; + return $this; + } + public function needWatchers($need_watchers) { $this->needWatchers = $need_watchers; return $this; @@ -169,10 +176,19 @@ final class PhabricatorProjectQuery protected function willExecute() { $this->slugMap = array(); $this->slugNormals = array(); + $this->allSlugs = array(); if ($this->slugs) { foreach ($this->slugs as $slug) { - $normal = PhabricatorSlug::normalizeProjectSlug($slug); - $this->slugNormals[$slug] = $normal; + if (PhabricatorSlug::isValidProjectSlug($slug)) { + $normal = PhabricatorSlug::normalizeProjectSlug($slug); + $this->slugNormals[$slug] = $normal; + $this->allSlugs[$normal] = $normal; + } + + // NOTE: At least for now, we query for the normalized slugs but also + // for the slugs exactly as entered. This allows older projects with + // slugs that are no longer valid to continue to work. + $this->allSlugs[$slug] = $slug; } } } @@ -210,8 +226,16 @@ final class PhabricatorProjectQuery $types[] = $watcher_type; } + $all_graph = $this->getAllReachableAncestors($projects); + + if ($this->needAncestorMembers) { + $src_projects = $all_graph; + } else { + $src_projects = $projects; + } + $all_sources = array(); - foreach ($projects as $project) { + foreach ($src_projects as $project) { if ($project->isMilestone()) { $phid = $project->getParentProjectPHID(); } else { @@ -224,10 +248,15 @@ final class PhabricatorProjectQuery ->withSourcePHIDs($all_sources) ->withEdgeTypes($types); + $need_all_edges = + $this->needMembers || + $this->needWatchers || + $this->needAncestorMembers; + // If we only need to know if the viewer is a member, we can restrict // the query to just their PHID. $any_edges = true; - if (!$this->needMembers && !$this->needWatchers) { + if (!$need_all_edges) { if ($viewer_phid) { $edge_query->withDestinationPHIDs(array($viewer_phid)); } else { @@ -243,7 +272,7 @@ final class PhabricatorProjectQuery } $membership_projects = array(); - foreach ($projects as $project) { + foreach ($src_projects as $project) { $project_phid = $project->getPHID(); if ($project->isMilestone()) { @@ -264,7 +293,7 @@ final class PhabricatorProjectQuery $membership_projects[$project_phid] = $project; } - if ($this->needMembers) { + if ($this->needMembers || $this->needAncestorMembers) { $project->attachMemberPHIDs($member_phids); } @@ -279,12 +308,15 @@ final class PhabricatorProjectQuery } } - $all_graph = $this->getAllReachableAncestors($projects); - $member_graph = $this->getAllReachableAncestors($membership_projects); + // If we loaded ancestor members, we've already populated membership + // lists above, so we can skip this step. + if (!$this->needAncestorMembers) { + $member_graph = $this->getAllReachableAncestors($membership_projects); - foreach ($all_graph as $phid => $project) { - $is_member = isset($member_graph[$phid]); - $project->setIsUserMember($viewer_phid, $is_member); + foreach ($all_graph as $phid => $project) { + $is_member = isset($member_graph[$phid]); + $project->setIsUserMember($viewer_phid, $is_member); + } } return $projects; @@ -380,7 +412,7 @@ final class PhabricatorProjectQuery $where[] = qsprintf( $conn, 'slug.slug IN (%Ls)', - $this->slugNormals); + $this->allSlugs); } if ($this->names !== null) { @@ -625,13 +657,17 @@ final class PhabricatorProjectQuery // else. $unknown = $this->slugNormals; foreach ($unknown as $input => $normal) { - if (!isset($primary_map[$normal])) { + if (isset($primary_map[$input])) { + $match = $input; + } else if (isset($primary_map[$normal])) { + $match = $normal; + } else { continue; } $this->slugMap[$input] = array( - 'slug' => $normal, - 'projectPHID' => $primary_map[$normal]->getPHID(), + 'slug' => $match, + 'projectPHID' => $primary_map[$match]->getPHID(), ); unset($unknown[$input]); @@ -658,13 +694,17 @@ final class PhabricatorProjectQuery // Link up any slugs we were not able to link up earlier. $extra_map = mpull($slugs, 'getProjectPHID', 'getSlug'); foreach ($unknown as $input => $normal) { - if (!isset($extra_map[$normal])) { + if (isset($extra_map[$input])) { + $match = $input; + } else if (isset($extra_map[$normal])) { + $match = $normal; + } else { continue; } $this->slugMap[$input] = array( - 'slug' => $normal, - 'projectPHID' => $extra_map[$normal], + 'slug' => $match, + 'projectPHID' => $extra_map[$match], ); unset($unknown[$input]); diff --git a/src/applications/project/query/PhabricatorProjectSearchEngine.php b/src/applications/project/query/PhabricatorProjectSearchEngine.php index eca90853cc..7d533c8a11 100644 --- a/src/applications/project/query/PhabricatorProjectSearchEngine.php +++ b/src/applications/project/query/PhabricatorProjectSearchEngine.php @@ -42,7 +42,7 @@ final class PhabricatorProjectSearchEngine } -protected function buildQueryFromParameters(array $map) { + protected function buildQueryFromParameters(array $map) { $query = $this->newQuery(); if (strlen($map['name'])) { @@ -155,8 +155,6 @@ protected function buildQueryFromParameters(array $map) { ->setType(PHUITagView::TYPE_SHADE) ->setShade($color) ->setName($name), - ' ', - $name, ); } diff --git a/src/applications/project/storage/PhabricatorProject.php b/src/applications/project/storage/PhabricatorProject.php index 99fe366583..97ed2765ef 100644 --- a/src/applications/project/storage/PhabricatorProject.php +++ b/src/applications/project/storage/PhabricatorProject.php @@ -6,12 +6,10 @@ final class PhabricatorProject extends PhabricatorProjectDAO PhabricatorFlaggableInterface, PhabricatorPolicyInterface, PhabricatorExtendedPolicyInterface, - PhabricatorSubscribableInterface, PhabricatorCustomFieldInterface, PhabricatorDestructibleInterface, PhabricatorFulltextInterface, - PhabricatorConduitResultInterface, - PhabricatorProfilePanelInterface { + PhabricatorConduitResultInterface { protected $name; protected $status = PhabricatorProjectStatus::STATUS_ACTIVE; @@ -46,8 +44,6 @@ final class PhabricatorProject extends PhabricatorProjectDAO private $slugs = self::ATTACHABLE; private $parentProject = self::ATTACHABLE; - const DEFAULT_COLOR = 'blue'; - const TABLE_DATASOURCE_TOKEN = 'project_datasourcetoken'; const PANEL_PROFILE = 'project.profile'; @@ -70,11 +66,12 @@ final class PhabricatorProject extends PhabricatorProjectDAO ProjectDefaultJoinCapability::CAPABILITY); $default_icon = PhabricatorProjectIconSet::getDefaultIconKey(); + $default_color = PhabricatorProjectIconSet::getDefaultColorKey(); return id(new PhabricatorProject()) ->setAuthorPHID($actor->getPHID()) ->setIcon($default_icon) - ->setColor(self::DEFAULT_COLOR) + ->setColor($default_color) ->setViewPolicy($view_policy) ->setEditPolicy($edit_policy) ->setJoinPolicy($join_policy) @@ -180,7 +177,6 @@ final class PhabricatorProject extends PhabricatorProjectDAO return $extended; } - public function isUserMember($user_phid) { if ($this->memberPHIDs !== self::ATTACHABLE) { return in_array($user_phid, $this->memberPHIDs); @@ -514,27 +510,26 @@ final class PhabricatorProject extends PhabricatorProjectDAO public function getDisplayColor() { if ($this->isMilestone()) { - return self::DEFAULT_COLOR; + return PhabricatorProjectIconSet::getDefaultColorKey(); } return $this->getColor(); } - -/* -( PhabricatorSubscribableInterface )----------------------------------- */ - - - public function isAutomaticallySubscribed($phid) { - return false; + public function getDisplayIconComposeIcon() { + $icon = $this->getDisplayIconIcon(); + return $icon; } - public function shouldShowSubscribersProperty() { - return false; - } + public function getDisplayIconComposeColor() { + $color = $this->getDisplayColor(); - public function shouldAllowSubscription($phid) { - return $this->isUserMember($phid) && - !$this->isUserWatcher($phid); + $map = array( + 'grey' => 'charcoal', + 'checkered' => 'backdrop', + ); + + return idx($map, $color, $color); } @@ -651,47 +646,4 @@ final class PhabricatorProject extends PhabricatorProjectDAO return array(); } - -/* -( PhabricatorProfilePanelInterface )----------------------------------- */ - - - public function getBuiltinProfilePanels() { - $panels = array(); - - $panels[] = PhabricatorProfilePanelConfiguration::initializeNewBuiltin() - ->setBuiltinKey(self::PANEL_PROFILE) - ->setPanelKey(PhabricatorProjectDetailsProfilePanel::PANELKEY); - - $panels[] = PhabricatorProfilePanelConfiguration::initializeNewBuiltin() - ->setBuiltinKey(self::PANEL_WORKBOARD) - ->setPanelKey(PhabricatorProjectWorkboardProfilePanel::PANELKEY); - - // TODO: This is temporary. - $uri = urisprintf( - '/maniphest/?statuses=open()&projects=%s#R', - $this->getPHID()); - - $panels[] = PhabricatorProfilePanelConfiguration::initializeNewBuiltin() - ->setBuiltinKey('tasks') - ->setPanelKey(PhabricatorLinkProfilePanel::PANELKEY) - ->setPanelProperty('icon', 'maniphest') - ->setPanelProperty('name', pht('Open Tasks')) - ->setPanelProperty('uri', $uri); - - // TODO: This is temporary. - $id = $this->getID(); - $panels[] = PhabricatorProfilePanelConfiguration::initializeNewBuiltin() - ->setBuiltinKey('feed') - ->setPanelKey(PhabricatorLinkProfilePanel::PANELKEY) - ->setPanelProperty('icon', 'feed') - ->setPanelProperty('name', pht('Feed')) - ->setPanelProperty('uri', "/project/feed/{$id}/"); - - $panels[] = PhabricatorProfilePanelConfiguration::initializeNewBuiltin() - ->setBuiltinKey(self::PANEL_MEMBERS) - ->setPanelKey(PhabricatorProjectMembersProfilePanel::PANELKEY); - - return $panels; - } - } diff --git a/src/applications/project/storage/PhabricatorProjectTransaction.php b/src/applications/project/storage/PhabricatorProjectTransaction.php index b16a4e30ca..1186e9c4f7 100644 --- a/src/applications/project/storage/PhabricatorProjectTransaction.php +++ b/src/applications/project/storage/PhabricatorProjectTransaction.php @@ -18,7 +18,6 @@ final class PhabricatorProjectTransaction const MAILTAG_METADATA = 'project-metadata'; const MAILTAG_MEMBERS = 'project-members'; - const MAILTAG_SUBSCRIBERS = 'project-subscribers'; const MAILTAG_WATCHERS = 'project-watchers'; const MAILTAG_OTHER = 'project-other'; @@ -382,9 +381,6 @@ final class PhabricatorProjectTransaction case self::TYPE_COLOR: $tags[] = self::MAILTAG_METADATA; break; - case PhabricatorTransactions::TYPE_SUBSCRIBERS: - $tags[] = self::MAILTAG_SUBSCRIBERS; - break; case PhabricatorTransactions::TYPE_EDGE: $type = $this->getMetadata('edge:type'); $type = head($type); diff --git a/src/applications/project/typeahead/PhabricatorProjectDatasource.php b/src/applications/project/typeahead/PhabricatorProjectDatasource.php index 64f0604b3f..9a18006e5c 100644 --- a/src/applications/project/typeahead/PhabricatorProjectDatasource.php +++ b/src/applications/project/typeahead/PhabricatorProjectDatasource.php @@ -65,13 +65,18 @@ final class PhabricatorProjectDatasource ->setName($all_strings) ->setDisplayName($proj->getName()) ->setDisplayType(pht('Project')) - ->setURI('/tag/'.$proj->getPrimarySlug().'/') + ->setURI($proj->getURI()) ->setPHID($proj->getPHID()) ->setIcon($proj->getDisplayIconIcon()) ->setColor($proj->getColor()) ->setPriorityType('proj') ->setClosed($closed); + $slug = $proj->getPrimarySlug(); + if (strlen($slug)) { + $proj_result->setAutocomplete('#'.$slug); + } + $proj_result->setImageURI($proj->getProfileImageURI()); $results[] = $proj_result; diff --git a/src/applications/project/view/PhabricatorProjectMemberListView.php b/src/applications/project/view/PhabricatorProjectMemberListView.php new file mode 100644 index 0000000000..12b7cc7a76 --- /dev/null +++ b/src/applications/project/view/PhabricatorProjectMemberListView.php @@ -0,0 +1,34 @@ +getUser(); + $project = $this->getProject(); + + if (!$project->supportsEditMembers()) { + return false; + } + + return PhabricatorPolicyFilter::hasCapability( + $viewer, + $project, + PhabricatorPolicyCapability::CAN_EDIT); + } + + protected function getNoDataString() { + return pht('This project does not have any members.'); + } + + protected function getRemoveURI($phid) { + $project = $this->getProject(); + $id = $project->getID(); + return "/project/members/{$id}/remove/?phid={$phid}"; + } + + protected function getHeaderText() { + return pht('Members'); + } + +} diff --git a/src/applications/project/view/PhabricatorProjectUserListView.php b/src/applications/project/view/PhabricatorProjectUserListView.php new file mode 100644 index 0000000000..138d51cbf3 --- /dev/null +++ b/src/applications/project/view/PhabricatorProjectUserListView.php @@ -0,0 +1,126 @@ +project = $project; + return $this; + } + + public function getProject() { + return $this->project; + } + + public function setUserPHIDs(array $user_phids) { + $this->userPHIDs = $user_phids; + return $this; + } + + public function getUserPHIDs() { + return $this->userPHIDs; + } + + public function setLimit($limit) { + $this->limit = $limit; + return $this; + } + + public function getLimit() { + return $this->limit; + } + + abstract protected function canEditList(); + abstract protected function getNoDataString(); + abstract protected function getRemoveURI($phid); + abstract protected function getHeaderText(); + + public function render() { + $viewer = $this->getUser(); + $project = $this->getProject(); + $user_phids = $this->getUserPHIDs(); + + $can_edit = $this->canEditList(); + $no_data = $this->getNoDataString(); + + $list = id(new PHUIObjectItemListView()) + ->setNoDataString($no_data); + + $limit = $this->getLimit(); + + // If we're showing everything, show oldest to newest. If we're showing + // only a slice, show newest to oldest. + if (!$limit) { + $user_phids = array_reverse($user_phids); + } + + $handles = $viewer->loadHandles($user_phids); + + // Always put the viewer first if they are on the list. + $user_phids = array_fuse($user_phids); + $user_phids = + array_select_keys($user_phids, array($viewer->getPHID())) + + $user_phids; + + if ($limit) { + $render_phids = array_slice($user_phids, 0, $limit); + } else { + $render_phids = $user_phids; + } + + foreach ($render_phids as $user_phid) { + $handle = $handles[$user_phid]; + + $item = id(new PHUIObjectItemView()) + ->setHeader($handle->getFullName()) + ->setHref($handle->getURI()) + ->setImageURI($handle->getImageURI()); + + if ($can_edit && !$limit) { + $remove_uri = $this->getRemoveURI($user_phid); + + $item->addAction( + id(new PHUIListItemView()) + ->setIcon('fa-times') + ->setName(pht('Remove')) + ->setHref($remove_uri) + ->setWorkflow(true)); + } + + $list->addItem($item); + } + + if ($user_phids) { + $header_text = pht( + '%s (%s)', + $this->getHeaderText(), + phutil_count($user_phids)); + } else { + $header_text = $this->getHeaderText(); + } + + $id = $project->getID(); + + $header = id(new PHUIHeaderView()) + ->setHeader($header_text); + + if ($limit) { + $header->addActionLink( + id(new PHUIButtonView()) + ->setTag('a') + ->setIcon( + id(new PHUIIconView()) + ->setIconFont('fa-list-ul')) + ->setText(pht('View All')) + ->setHref("/project/members/{$id}/")); + } + + return id(new PHUIObjectBoxView()) + ->setHeader($header) + ->setObjectList($list); + } + +} diff --git a/src/applications/project/view/PhabricatorProjectWatcherListView.php b/src/applications/project/view/PhabricatorProjectWatcherListView.php new file mode 100644 index 0000000000..7aa9638afc --- /dev/null +++ b/src/applications/project/view/PhabricatorProjectWatcherListView.php @@ -0,0 +1,30 @@ +getUser(); + $project = $this->getProject(); + + return PhabricatorPolicyFilter::hasCapability( + $viewer, + $project, + PhabricatorPolicyCapability::CAN_EDIT); + } + + protected function getNoDataString() { + return pht('This project does not have any watchers.'); + } + + protected function getRemoveURI($phid) { + $project = $this->getProject(); + $id = $project->getID(); + return "/project/watchers/{$id}/remove/?phid={$phid}"; + } + + protected function getHeaderText() { + return pht('Watchers'); + } + +} diff --git a/src/applications/repository/storage/PhabricatorRepositoryCommit.php b/src/applications/repository/storage/PhabricatorRepositoryCommit.php index fc67d8b7b3..348b94d021 100644 --- a/src/applications/repository/storage/PhabricatorRepositoryCommit.php +++ b/src/applications/repository/storage/PhabricatorRepositoryCommit.php @@ -443,10 +443,6 @@ final class PhabricatorRepositoryCommit return true; } - public function shouldAllowSubscription($phid) { - return true; - } - /* -( PhabricatorApplicationTransactionInterface )------------------------- */ diff --git a/src/applications/search/controller/PhabricatorApplicationSearchController.php b/src/applications/search/controller/PhabricatorApplicationSearchController.php index 186e6474cd..3b30d5d30c 100644 --- a/src/applications/search/controller/PhabricatorApplicationSearchController.php +++ b/src/applications/search/controller/PhabricatorApplicationSearchController.php @@ -100,7 +100,7 @@ final class PhabricatorApplicationSearchController } else if (!strlen($this->queryKey)) { $found_query_data = false; - if ($request->isHTTPGet()) { + if ($request->isHTTPGet() || $request->isQuicksand()) { // If this is a GET request and it has some query data, don't // do anything unless it's only before= or after=. We'll build and // execute a query from it below. This allows external tools to build diff --git a/src/applications/search/editor/PhabricatorProfilePanelEditEngine.php b/src/applications/search/editor/PhabricatorProfilePanelEditEngine.php index 7713a97f7c..3a2f725719 100644 --- a/src/applications/search/editor/PhabricatorProfilePanelEditEngine.php +++ b/src/applications/search/editor/PhabricatorProfilePanelEditEngine.php @@ -23,8 +23,7 @@ final class PhabricatorProfilePanelEditEngine return $this->panelEngine; } - public function setProfileObject( - PhabricatorProfilePanelInterface $profile_object) { + public function setProfileObject($profile_object) { $this->profileObject = $profile_object; return $this; } diff --git a/src/applications/search/engine/PhabricatorProfilePanelEngine.php b/src/applications/search/engine/PhabricatorProfilePanelEngine.php index 760665e5b2..3622e43976 100644 --- a/src/applications/search/engine/PhabricatorProfilePanelEngine.php +++ b/src/applications/search/engine/PhabricatorProfilePanelEngine.php @@ -1,11 +1,13 @@ viewer = $viewer; @@ -16,8 +18,7 @@ final class PhabricatorProfilePanelEngine extends Phobject { return $this->viewer; } - public function setProfileObject( - PhabricatorProfilePanelInterface $profile_object) { + public function setProfileObject($profile_object) { $this->profileObject = $profile_object; return $this; } @@ -35,6 +36,23 @@ final class PhabricatorProfilePanelEngine extends Phobject { return $this->controller; } + private function setDefaultPanel( + PhabricatorProfilePanelConfiguration $default_panel) { + $this->defaultPanel = $default_panel; + return $this; + } + + public function getDefaultPanel() { + $this->loadPanels(); + return $this->defaultPanel; + } + + abstract protected function getPanelURI($path); + + protected function isPanelEngineConfigurable() { + return PhabricatorEnv::getEnvConfig('phabricator.show-prototypes'); + } + public function buildResponse() { $controller = $this->getController(); @@ -44,6 +62,18 @@ final class PhabricatorProfilePanelEngine extends Phobject { $request = $controller->getRequest(); $panel_action = $request->getURIData('panelAction'); + + // If the engine is not configurable, don't respond to any of the editing + // or configuration routes. + if (!$this->isPanelEngineConfigurable()) { + switch ($panel_action) { + case 'view': + break; + default: + return new Aphront404Response(); + } + } + $panel_id = $request->getURIData('panelID'); $panel_list = $this->loadPanels(); @@ -71,6 +101,7 @@ final class PhabricatorProfilePanelEngine extends Phobject { case 'view': case 'info': case 'hide': + case 'default': case 'builtin': if (!$selected_panel) { return new Aphront404Response(); @@ -104,6 +135,11 @@ final class PhabricatorProfilePanelEngine extends Phobject { case 'hide': $content = $this->buildPanelHideContent($selected_panel); break; + case 'default': + $content = $this->buildPanelDefaultContent( + $selected_panel, + $panel_list); + break; case 'edit': $content = $this->buildPanelEditContent(); break; @@ -130,9 +166,13 @@ final class PhabricatorProfilePanelEngine extends Phobject { } public function buildNavigation() { + if ($this->navigation) { + return $this->navigation; + } + $nav = id(new AphrontSideNavFilterView()) - ->setIconNav(true) - ->setBaseURI(new PhutilURI('/project/')); + ->setIsProfileMenu(true) + ->setBaseURI(new PhutilURI($this->getPanelURI(''))); $panels = $this->getPanels(); @@ -168,14 +208,15 @@ final class PhabricatorProfilePanelEngine extends Phobject { } } - $configure_item = $this->newConfigureMenuItem(); - if ($configure_item) { - $nav->addMenuItem($configure_item); + $more_items = $this->newAutomaticMenuItems($nav); + foreach ($more_items as $item) { + $nav->addMenuItem($item); } $nav->selectFilter(null); - return $nav; + $this->navigation = $nav; + return $this->navigation; } private function getPanels() { @@ -202,7 +243,15 @@ final class PhabricatorProfilePanelEngine extends Phobject { foreach ($stored_panels as $stored_panel) { $builtin_key = $stored_panel->getBuiltinKey(); if ($builtin_key !== null) { - $panels[$builtin_key] = $stored_panel; + // If this builtin actually exists, replace the builtin with the + // stored configuration. Otherwise, we're just going to drop the + // stored config: it corresponds to an out-of-date or uninstalled + // panel. + if (isset($panels[$builtin_key])) { + $panels[$builtin_key] = $stored_panel; + } else { + continue; + } } else { $panels[] = $stored_panel; } @@ -220,12 +269,39 @@ final class PhabricatorProfilePanelEngine extends Phobject { // partially keyed. $panels = array_values($panels); + + // Make sure exactly one valid panel is marked as default. + $default = null; + $first = null; + foreach ($panels as $panel) { + if (!$panel->canMakeDefault()) { + continue; + } + + if ($panel->isDefault()) { + $default = $panel; + break; + } + + if ($first === null) { + $first = $panel; + } + } + + if (!$default) { + $default = $first; + } + + if ($default) { + $this->setDefaultPanel($default); + } + return $panels; } private function loadBuiltinProfilePanels() { $object = $this->getProfileObject(); - $builtins = $object->getBuiltinProfilePanels(); + $builtins = $this->getBuiltinProfilePanels($object); $panels = PhabricatorProfilePanel::getAllPanels(); @@ -284,39 +360,118 @@ final class PhabricatorProfilePanelEngine extends Phobject { } } - private function newConfigureMenuItem() { - if (!PhabricatorEnv::getEnvConfig('phabricator.show-prototypes')) { - return null; + private function newAutomaticMenuItems(AphrontSideNavFilterView $nav) { + $items = array(); + + // NOTE: We're adding a spacer item for the fixed footer, so that if the + // menu taller than the page content you can still scroll down the page far + // enough to access the last item without the content being obscured by the + // fixed items. + $items[] = id(new PHUIListItemView()) + ->setHideInApplicationMenu(true) + ->addClass('phui-profile-menu-spacer'); + + if ($this->isPanelEngineConfigurable()) { + $viewer = $this->getViewer(); + $object = $this->getProfileObject(); + + $can_edit = PhabricatorPolicyFilter::hasCapability( + $viewer, + $object, + PhabricatorPolicyCapability::CAN_EDIT); + + $expanded_edit_icon = id(new PHUIIconCircleView()) + ->addClass('phui-list-item-icon') + ->addClass('phui-profile-menu-visible-when-expanded') + ->setIconFont('fa-pencil'); + + $collapsed_edit_icon = id(new PHUIIconCircleView()) + ->addClass('phui-list-item-icon') + ->addClass('phui-profile-menu-visible-when-collapsed') + ->setIconFont('fa-pencil') + ->addSigil('has-tooltip') + ->setMetadata( + array( + 'tip' => pht('Edit Menu'), + 'align' => 'E', + )); + + $items[] = id(new PHUIListItemView()) + ->setName('Edit Menu') + ->setKey('panel.configure') + ->addIcon($expanded_edit_icon) + ->addIcon($collapsed_edit_icon) + ->addClass('phui-profile-menu-footer') + ->addClass('phui-profile-menu-footer-1') + ->setHref($this->getPanelURI('configure/')) + ->setDisabled(!$can_edit) + ->setWorkflow(!$can_edit); } + $collapse_id = celerity_generate_unique_node_id(); + $viewer = $this->getViewer(); - $object = $this->getProfileObject(); - $can_edit = PhabricatorPolicyFilter::hasCapability( - $viewer, - $object, - PhabricatorPolicyCapability::CAN_EDIT); + $collapse_key = + PhabricatorUserPreferences::PREFERENCE_PROFILE_MENU_COLLAPSED; - return id(new PHUIListItemView()) - ->setName('Configure Menu') - ->setKey('panel.configure') - ->setIcon('fa-gear') - ->setHref($this->getPanelURI('configure/')) - ->setDisabled(!$can_edit) - ->setWorkflow(!$can_edit) - ->setRenderNameAsTooltip(true); + $preferences = $viewer->loadPreferences(); + $is_collapsed = $preferences->getPreference($collapse_key, false); + + if ($is_collapsed) { + $nav->addClass('phui-profile-menu-collapsed'); + } else { + $nav->addClass('phui-profile-menu-expanded'); + } + + if ($viewer->isLoggedIn()) { + $settings_uri = '/settings/adjust/?key='.$collapse_key; + } else { + $settings_uri = null; + } + + Javelin::initBehavior( + 'phui-profile-menu', + array( + 'menuID' => $nav->getMainID(), + 'collapseID' => $collapse_id, + 'isCollapsed' => (bool)$is_collapsed, + 'settingsURI' => $settings_uri, + )); + + $collapse_icon = id(new PHUIIconCircleView()) + ->addClass('phui-list-item-icon') + ->addClass('phui-profile-menu-visible-when-expanded') + ->setIconFont('fa-angle-left'); + + $expand_icon = id(new PHUIIconCircleView()) + ->addClass('phui-list-item-icon') + ->addClass('phui-profile-menu-visible-when-collapsed') + ->addSigil('has-tooltip') + ->setMetadata( + array( + 'tip' => pht('Expand'), + 'align' => 'E', + )) + ->setIconFont('fa-angle-right'); + + $items[] = id(new PHUIListItemView()) + ->setName('Collapse') + ->addIcon($collapse_icon) + ->addIcon($expand_icon) + ->setID($collapse_id) + ->addClass('phui-profile-menu-footer') + ->addClass('phui-profile-menu-footer-2') + ->setHideInApplicationMenu(true) + ->setHref('#'); + + return $items; } public function getConfigureURI() { return $this->getPanelURI('configure/'); } - private function getPanelURI($path) { - $project = $this->getProfileObject(); - $id = $project->getID(); - return "/project/{$id}/panel/{$path}"; - } - private function buildPanelReorderContent(array $panels) { $viewer = $this->getViewer(); $object = $this->getProfileObject(); @@ -440,6 +595,31 @@ final class PhabricatorProfilePanelEngine extends Phobject { 'key' => nonempty($id, $builtin_key), )); + if ($id) { + $default_uri = $this->getPanelURI("default/{$id}/"); + } else { + $default_uri = $this->getPanelURI("default/{$builtin_key}/"); + } + + if ($panel->isDefault()) { + $default_icon = 'fa-thumb-tack green'; + $default_text = pht('Current Default'); + } else if ($panel->canMakeDefault()) { + $default_icon = 'fa-thumb-tack'; + $default_text = pht('Make Default'); + } else { + $default_text = null; + } + + if ($default_text !== null) { + $item->addAction( + id(new PHUIListItemView()) + ->setHref($default_uri) + ->setWorkflow(true) + ->setName($default_text) + ->setIcon($default_icon)); + } + if ($id) { $item->setHref($this->getPanelURI("edit/{$id}/")); $hide_uri = $this->getPanelURI("hide/{$id}/"); @@ -448,16 +628,27 @@ final class PhabricatorProfilePanelEngine extends Phobject { $hide_uri = $this->getPanelURI("hide/{$builtin_key}/"); } + if ($panel->isDisabled()) { + $hide_icon = 'fa-plus'; + $hide_text = pht('Enable'); + } else if ($panel->getBuiltinKey() !== null) { + $hide_icon = 'fa-times'; + $hide_text = pht('Disable'); + } else { + $hide_icon = 'fa-times'; + $hide_text = pht('Delete'); + } + $item->addAction( id(new PHUIListItemView()) ->setHref($hide_uri) ->setWorkflow(true) - ->setIcon(pht('fa-eye'))); + ->setName($hide_text) + ->setIcon($hide_icon)); } if ($panel->isDisabled()) { $item->setDisabled(true); - $item->addIcon('fa-times grey', pht('Disabled')); } $list->addItem($item); @@ -492,10 +683,14 @@ final class PhabricatorProfilePanelEngine extends Phobject { ->setLabel(true) ->setName(pht('Documentation'))); + $doc_link = PhabricatorEnv::getDoclink('Profile Menu User Guide'); + $doc_name = pht('Profile Menu User Guide'); + $action_view->addAction( id(new PhabricatorActionView()) ->setIcon('fa-book') - ->setName(pht('TODO: Write Documentation'))); + ->setHref($doc_link) + ->setName($doc_name)); $action_button = id(new PHUIButtonView()) ->setTag('a') @@ -605,46 +800,186 @@ final class PhabricatorProfilePanelEngine extends Phobject { $configuration, PhabricatorPolicyCapability::CAN_EDIT); + if ($configuration->getBuiltinKey() === null) { + $new_value = null; + + $title = pht('Delete Menu Item'); + $body = pht('Delete this menu item?'); + $button = pht('Delete Menu Item'); + } else if ($configuration->isDisabled()) { + $new_value = PhabricatorProfilePanelConfiguration::VISIBILITY_VISIBLE; + + $title = pht('Enable Menu Item'); + $body = pht( + 'Enable this menu item? It will appear in the menu again.'); + $button = pht('Enable Menu Item'); + } else { + $new_value = PhabricatorProfilePanelConfiguration::VISIBILITY_DISABLED; + + $title = pht('Disable Menu Item'); + $body = pht( + 'Disable this menu item? It will no longer appear in the menu, but '. + 'you can re-enable it later.'); + $button = pht('Disable Menu Item'); + } + $v_visibility = $configuration->getVisibility(); if ($request->isFormPost()) { - $v_visibility = $request->getStr('visibility'); + if ($new_value === null) { + $configuration->delete(); + } else { + $type_visibility = + PhabricatorProfilePanelConfigurationTransaction::TYPE_VISIBILITY; - $type_visibility = - PhabricatorProfilePanelConfigurationTransaction::TYPE_VISIBILITY; + $xactions = array(); - $xactions = array(); + $xactions[] = id(new PhabricatorProfilePanelConfigurationTransaction()) + ->setTransactionType($type_visibility) + ->setNewValue($new_value); - $xactions[] = id(new PhabricatorProfilePanelConfigurationTransaction()) - ->setTransactionType($type_visibility) - ->setNewValue($v_visibility); - - $editor = id(new PhabricatorProfilePanelEditor()) - ->setContentSourceFromRequest($request) - ->setActor($viewer) - ->setContinueOnMissingFields(true) - ->setContinueOnNoEffect(true) - ->applyTransactions($configuration, $xactions); + $editor = id(new PhabricatorProfilePanelEditor()) + ->setContentSourceFromRequest($request) + ->setActor($viewer) + ->setContinueOnMissingFields(true) + ->setContinueOnNoEffect(true) + ->applyTransactions($configuration, $xactions); + } return id(new AphrontRedirectResponse()) ->setURI($this->getConfigureURI()); } - $map = PhabricatorProfilePanelConfiguration::getVisibilityNameMap(); + return $controller->newDialog() + ->setTitle($title) + ->appendParagraph($body) + ->addCancelButton($this->getConfigureURI()) + ->addSubmitButton($button); + } - $form = id(new AphrontFormView()) - ->setUser($viewer) - ->appendControl( - id(new AphrontFormSelectControl()) - ->setName('visibility') - ->setLabel(pht('Visibility')) - ->setValue($v_visibility) - ->setOptions($map)); + private function buildPanelDefaultContent( + PhabricatorProfilePanelConfiguration $configuration, + array $panels) { + + $controller = $this->getController(); + $request = $controller->getRequest(); + $viewer = $this->getViewer(); + + PhabricatorPolicyFilter::requireCapability( + $viewer, + $configuration, + PhabricatorPolicyCapability::CAN_EDIT); + + $done_uri = $this->getConfigureURI(); + + if (!$configuration->canMakeDefault()) { + return $controller->newDialog() + ->setTitle(pht('Not Defaultable')) + ->appendParagraph( + pht( + 'This item can not be set as the default item. This is usually '. + 'because the item has no page of its own, or links to an '. + 'external page.')) + ->addCancelButton($done_uri); + } + + if ($configuration->isDefault()) { + return $controller->newDialog() + ->setTitle(pht('Already Default')) + ->appendParagraph( + pht( + 'This item is already set as the default item for this menu.')) + ->addCancelButton($done_uri); + } + + if ($request->isFormPost()) { + $key = $configuration->getID(); + if (!$key) { + $key = $configuration->getBuiltinKey(); + } + + $this->adjustDefault($key); + + return id(new AphrontRedirectResponse()) + ->setURI($done_uri); + } return $controller->newDialog() - ->setTitle(pht('Change Item Visibility')) - ->appendForm($form) - ->addCancelButton($this->getConfigureURI()) - ->addSubmitButton(pht('Save Changes')); + ->setTitle(pht('Make Default')) + ->appendParagraph( + pht( + 'Set this item as the default for this menu? Users arriving on '. + 'this page will be shown the content of this item by default.')) + ->addCancelButton($done_uri) + ->addSubmitButton(pht('Make Default')); + } + + protected function newPanel() { + return PhabricatorProfilePanelConfiguration::initializeNewBuiltin(); + } + + public function adjustDefault($key) { + $controller = $this->getController(); + $request = $controller->getRequest(); + $viewer = $request->getViewer(); + + $panels = $this->loadPanels(); + + // To adjust the default panel, we first change any existing panels that + // are marked as defaults to "visible", then make the new default panel + // the default. + + $default = array(); + $visible = array(); + + foreach ($panels as $panel) { + $builtin_key = $panel->getBuiltinKey(); + $id = $panel->getID(); + + $is_target = + (($builtin_key !== null) && ($builtin_key === $key)) || + (($id !== null) && ($id === (int)$key)); + + if ($is_target) { + if (!$panel->isDefault()) { + $default[] = $panel; + } + } else { + if ($panel->isDefault()) { + $visible[] = $panel; + } + } + } + + $type_visibility = + PhabricatorProfilePanelConfigurationTransaction::TYPE_VISIBILITY; + + $v_visible = PhabricatorProfilePanelConfiguration::VISIBILITY_VISIBLE; + $v_default = PhabricatorProfilePanelConfiguration::VISIBILITY_DEFAULT; + + $apply = array( + array($v_visible, $visible), + array($v_default, $default), + ); + + foreach ($apply as $group) { + list($value, $panels) = $group; + foreach ($panels as $panel) { + $xactions = array(); + + $xactions[] = id(new PhabricatorProfilePanelConfigurationTransaction()) + ->setTransactionType($type_visibility) + ->setNewValue($value); + + $editor = id(new PhabricatorProfilePanelEditor()) + ->setContentSourceFromRequest($request) + ->setActor($viewer) + ->setContinueOnMissingFields(true) + ->setContinueOnNoEffect(true) + ->applyTransactions($panel, $xactions); + } + } + + return $this; } } diff --git a/src/applications/search/interface/PhabricatorProfilePanelInterface.php b/src/applications/search/interface/PhabricatorProfilePanelInterface.php deleted file mode 100644 index 34d68458a8..0000000000 --- a/src/applications/search/interface/PhabricatorProfilePanelInterface.php +++ /dev/null @@ -1,7 +0,0 @@ -setValue( + pht( + 'This is a visual divider which you can use to separate '. + 'sections in the menu. It does not have any configurable '. + 'options.')), + ); + } + + protected function newNavigationMenuItems( + PhabricatorProfilePanelConfiguration $config) { + + $item = $this->newItem() + ->addClass('phui-divider'); + + return array( + $item, + ); + } + +} diff --git a/src/applications/search/profilepanel/PhabricatorLinkProfilePanel.php b/src/applications/search/profilepanel/PhabricatorLinkProfilePanel.php index d2b19ad368..18654dccd3 100644 --- a/src/applications/search/profilepanel/PhabricatorLinkProfilePanel.php +++ b/src/applications/search/profilepanel/PhabricatorLinkProfilePanel.php @@ -13,8 +13,7 @@ final class PhabricatorLinkProfilePanel return pht('Link'); } - public function canAddToObject( - PhabricatorProfilePanelInterface $object) { + public function canAddToObject($object) { return true; } @@ -82,9 +81,7 @@ final class PhabricatorLinkProfilePanel $icon_class = 'fa-link'; } - $item = id(new PHUIListItemView()) - ->setRenderNameAsTooltip(true) - ->setType(PHUIListItemView::TYPE_ICON_NAV) + $item = $this->newItem() ->setHref($href) ->setName($name) ->setIcon($icon_class); diff --git a/src/applications/search/profilepanel/PhabricatorMotivatorProfilePanel.php b/src/applications/search/profilepanel/PhabricatorMotivatorProfilePanel.php new file mode 100644 index 0000000000..73668fdd41 --- /dev/null +++ b/src/applications/search/profilepanel/PhabricatorMotivatorProfilePanel.php @@ -0,0 +1,151 @@ +getOptions(); + $name = idx($options, $config->getPanelProperty('source')); + if ($name !== null) { + return pht('Motivator: %s', $name); + } else { + return pht('Motivator'); + } + } + + public function buildEditEngineFields( + PhabricatorProfilePanelConfiguration $config) { + return array( + id(new PhabricatorInstructionsEditField()) + ->setValue( + pht( + 'Motivate your team with inspirational quotes from great minds. '. + 'This panel shows a new quote every day.')), + id(new PhabricatorSelectEditField()) + ->setKey('source') + ->setLabel(pht('Source')) + ->setOptions($this->getOptions()), + ); + } + + private function getOptions() { + return array( + 'catfacts' => pht('Cat Facts'), + ); + } + + protected function newNavigationMenuItems( + PhabricatorProfilePanelConfiguration $config) { + + $source = $config->getPanelProperty('source'); + + switch ($source) { + case 'catfacts': + default: + $facts = $this->getCatFacts(); + break; + } + + $fact = $this->selectFact($facts); + + switch ($source) { + case 'catfacts': + default: + $fact = array( + id(new PHUIIconView())->setIconFont('fa-paw'), + ' ', + $fact, + ); + break; + } + + $fact = phutil_tag( + 'div', + array( + 'class' => 'phui-motivator', + ), + $fact); + + $item = $this->newItem() + ->appendChild($fact); + + return array( + $item, + ); + } + + private function getCatFacts() { + return array( + pht('Cats purr when they are happy, upset, or asleep.'), + pht('The first cats evolved on the savanah about 8,000 years ago.'), + pht( + 'Cats have a tail, two feet, between one and three ears, and two '. + 'other feet.'), + pht('Cats use their keen sense of smell to avoid feeling empathy.'), + pht('The first cats evolved in swamps about 65 years ago.'), + pht( + 'You can tell how warm a cat is by examining the coloration: cooler '. + 'areas are darker.'), + pht( + 'Cat tails are flexible because they contain thousands of tiny '. + 'bones.'), + pht( + 'A cattail is a wetland plant with an appearance that resembles '. + 'the tail of a cat.'), + pht( + 'Cats must eat a diet rich in fish to replace the tiny bones in '. + 'their tails.'), + pht('Cats are stealthy predators and nearly invisible to radar.'), + pht( + 'Cats use a special type of magnetism to help them land on their '. + 'feet.'), + pht( + 'A cat can run seven times faster than a human, but only for a '. + 'short distance.'), + pht( + 'The largest recorded cat was nearly 11 inches long from nose to '. + 'tail.'), + pht( + 'Not all cats can retract their claws, but most of them can.'), + pht( + 'In the wild, cats and racoons sometimes hunt together in packs.'), + pht( + 'The Spanish word for cat is "cato". The biggest cat is called '. + '"el cato".'), + pht( + 'The Japanese word for cat is "kome", which is also the word for '. + 'rice. Japanese cats love to eat rice, so the two are synonymous.'), + ); + } + + private function selectFact(array $facts) { + // This is a simple pseudorandom number generator that avoids touching + // srand(), because it would seed it to a highly predictable value. It + // selects a new fact every day. + + $seed = ((int)date('Y') * 366) + (int)date('z'); + for ($ii = 0; $ii < 32; $ii++) { + $seed = ((1664525 * $seed) + 1013904223) % (1 << 31); + } + + return $facts[$seed % count($facts)]; + } + + +} diff --git a/src/applications/search/profilepanel/PhabricatorProfilePanel.php b/src/applications/search/profilepanel/PhabricatorProfilePanel.php index 6f029927d8..49159dbf8d 100644 --- a/src/applications/search/profilepanel/PhabricatorProfilePanel.php +++ b/src/applications/search/profilepanel/PhabricatorProfilePanel.php @@ -26,8 +26,12 @@ abstract class PhabricatorProfilePanel extends Phobject { return array(); } - public function canAddToObject( - PhabricatorProfilePanelInterface $object) { + public function canAddToObject($object) { + return false; + } + + public function canMakeDefault( + PhabricatorProfilePanelConfiguration $config) { return false; } @@ -51,4 +55,8 @@ abstract class PhabricatorProfilePanel extends Phobject { ->execute(); } + protected function newItem() { + return new PHUIListItemView(); + } + } diff --git a/src/applications/search/profilepanel/PhabricatorProfilePanelIconSet.php b/src/applications/search/profilepanel/PhabricatorProfilePanelIconSet.php index 19b164e932..bc3b15a7cf 100644 --- a/src/applications/search/profilepanel/PhabricatorProfilePanelIconSet.php +++ b/src/applications/search/profilepanel/PhabricatorProfilePanelIconSet.php @@ -26,6 +26,36 @@ final class PhabricatorProfilePanelIconSet 'icon' => 'fa-newspaper-o', 'name' => pht('Feed'), ), + array( + 'key' => 'phriction', + 'icon' => 'fa-book', + 'name' => pht('Phriction'), + ), + array( + 'key' => 'conpherence', + 'icon' => 'fa-comments', + 'name' => pht('Conpherence'), + ), + array( + 'key' => 'differential', + 'icon' => 'fa-cog', + 'name' => pht('Differential'), + ), + array( + 'key' => 'diffusion', + 'icon' => 'fa-code', + 'name' => pht('Diffusion'), + ), + array( + 'key' => 'calendar', + 'icon' => 'fa-calendar', + 'name' => pht('Calendar'), + ), + array( + 'key' => 'create', + 'icon' => 'fa-plus', + 'name' => pht('Create'), + ), ); $icons = array(); diff --git a/src/applications/search/query/PhabricatorProfilePanelConfigurationTransactionQuery.php b/src/applications/search/query/PhabricatorProfilePanelConfigurationTransactionQuery.php new file mode 100644 index 0000000000..dba7120d1d --- /dev/null +++ b/src/applications/search/query/PhabricatorProfilePanelConfigurationTransactionQuery.php @@ -0,0 +1,10 @@ + pht('Visible'), - self::VISIBILITY_DISABLED => pht('Disabled'), - ); - } - public function generatePHID() { return PhabricatorPHID::generateNewPHID( PhabricatorProfilePanelPHIDType::TYPECONST); @@ -77,8 +71,7 @@ final class PhabricatorProfilePanelConfiguration return $this->assertAttached($this->panel); } - public function attachProfileObject( - PhabricatorProfilePanelInterface $profile_object) { + public function attachProfileObject($profile_object) { $this->profileObject = $profile_object; return $this; } @@ -108,6 +101,10 @@ final class PhabricatorProfilePanelConfiguration return $this->getPanel()->getDisplayName($this); } + public function canMakeDefault() { + return $this->getPanel()->canMakeDefault($this); + } + public function getSortKey() { $order = $this->getPanelOrder(); if ($order === null) { @@ -126,6 +123,10 @@ final class PhabricatorProfilePanelConfiguration return ($this->getVisibility() === self::VISIBILITY_DISABLED); } + public function isDefault() { + return ($this->getVisibility() === self::VISIBILITY_DEFAULT); + } + /* -( PhabricatorPolicyInterface )----------------------------------------- */ diff --git a/src/applications/settings/storage/PhabricatorUserPreferences.php b/src/applications/settings/storage/PhabricatorUserPreferences.php index 1527f2844d..53c080ec88 100644 --- a/src/applications/settings/storage/PhabricatorUserPreferences.php +++ b/src/applications/settings/storage/PhabricatorUserPreferences.php @@ -41,6 +41,8 @@ final class PhabricatorUserPreferences extends PhabricatorUserDAO { const PREFERENCE_RESOURCE_POSTPROCESSOR = 'resource-postprocessor'; const PREFERENCE_DESKTOP_NOTIFICATIONS = 'desktop-notifications'; + const PREFERENCE_PROFILE_MENU_COLLAPSED = 'profile-menu.collapsed'; + // These are in an unusual order for historic reasons. const MAILTAG_PREFERENCE_NOTIFY = 0; const MAILTAG_PREFERENCE_EMAIL = 1; diff --git a/src/applications/slowvote/storage/PhabricatorSlowvotePoll.php b/src/applications/slowvote/storage/PhabricatorSlowvotePoll.php index 12f4f9e984..2240c510aa 100644 --- a/src/applications/slowvote/storage/PhabricatorSlowvotePoll.php +++ b/src/applications/slowvote/storage/PhabricatorSlowvotePoll.php @@ -183,10 +183,6 @@ final class PhabricatorSlowvotePoll extends PhabricatorSlowvoteDAO return true; } - public function shouldAllowSubscription($phid) { - return true; - } - /* -( PhabricatorTokenReceiverInterface )---------------------------------- */ diff --git a/src/applications/subscriptions/controller/PhabricatorSubscriptionsEditController.php b/src/applications/subscriptions/controller/PhabricatorSubscriptionsEditController.php index 3723a755be..ad089d8f3d 100644 --- a/src/applications/subscriptions/controller/PhabricatorSubscriptionsEditController.php +++ b/src/applications/subscriptions/controller/PhabricatorSubscriptionsEditController.php @@ -61,13 +61,6 @@ final class PhabricatorSubscriptionsEditController $handle->getURI()); } - if (!$object->shouldAllowSubscription($viewer->getPHID())) { - return $this->buildErrorResponse( - pht('You Can Not Subscribe'), - pht('You can not subscribe to this object.'), - $handle->getURI()); - } - if ($object instanceof PhabricatorApplicationTransactionInterface) { if ($is_add) { $xaction_value = array( diff --git a/src/applications/subscriptions/events/PhabricatorSubscriptionsUIEventListener.php b/src/applications/subscriptions/events/PhabricatorSubscriptionsUIEventListener.php index fb7c32892f..b69ce4243f 100644 --- a/src/applications/subscriptions/events/PhabricatorSubscriptionsUIEventListener.php +++ b/src/applications/subscriptions/events/PhabricatorSubscriptionsUIEventListener.php @@ -34,11 +34,6 @@ final class PhabricatorSubscriptionsUIEventListener return; } - if (!$object->shouldAllowSubscription($user_phid)) { - // This object doesn't allow the viewer to subscribe. - return; - } - if ($user_phid && $object->isAutomaticallySubscribed($user_phid)) { $sub_action = id(new PhabricatorActionView()) ->setWorkflow(true) diff --git a/src/applications/subscriptions/interface/PhabricatorSubscribableInterface.php b/src/applications/subscriptions/interface/PhabricatorSubscribableInterface.php index 95275e53bb..e54e2cd42e 100644 --- a/src/applications/subscriptions/interface/PhabricatorSubscribableInterface.php +++ b/src/applications/subscriptions/interface/PhabricatorSubscribableInterface.php @@ -22,17 +22,6 @@ interface PhabricatorSubscribableInterface { */ public function shouldShowSubscribersProperty(); - - /** - * Return `true` to indicate that the "Subscribe" action should be shown and - * enabled when rendering action lists for this object, or `false` to omit - * the action. - * - * @param phid Viewing or acting user PHID. - * @return bool True to allow the user to subscribe. - */ - public function shouldAllowSubscription($phid); - } // TEMPLATE IMPLEMENTATION ///////////////////////////////////////////////////// @@ -48,8 +37,4 @@ interface PhabricatorSubscribableInterface { return true; } - public function shouldAllowSubscription($phid) { - return true; - } - */ diff --git a/src/applications/transactions/editfield/PhabricatorStringListEditField.php b/src/applications/transactions/editfield/PhabricatorStringListEditField.php index 64cb1fe08c..74046be7ac 100644 --- a/src/applications/transactions/editfield/PhabricatorStringListEditField.php +++ b/src/applications/transactions/editfield/PhabricatorStringListEditField.php @@ -7,6 +7,11 @@ final class PhabricatorStringListEditField return new AphrontFormTextControl(); } + protected function getValueForControl() { + $value = $this->getValue(); + return implode(', ', $value); + } + protected function newConduitParameterType() { return new ConduitStringListParameterType(); } diff --git a/src/applications/typeahead/storage/PhabricatorTypeaheadResult.php b/src/applications/typeahead/storage/PhabricatorTypeaheadResult.php index 6ef913fc5a..f5c84766b7 100644 --- a/src/applications/typeahead/storage/PhabricatorTypeaheadResult.php +++ b/src/applications/typeahead/storage/PhabricatorTypeaheadResult.php @@ -16,6 +16,7 @@ final class PhabricatorTypeaheadResult extends Phobject { private $closed; private $tokenType; private $unique; + private $autocomplete; public function setIcon($icon) { $this->icon = $icon; @@ -114,6 +115,15 @@ final class PhabricatorTypeaheadResult extends Phobject { return $this->color; } + public function setAutocomplete($autocomplete) { + $this->autocomplete = $autocomplete; + return $this; + } + + public function getAutocomplete() { + return $this->autocomplete; + } + public function getSortKey() { // Put unique results (special parameter functions) ahead of other // results. @@ -142,6 +152,7 @@ final class PhabricatorTypeaheadResult extends Phobject { $this->color, $this->tokenType, $this->unique ? 1 : null, + $this->autocomplete, ); while (end($data) === null) { array_pop($data); diff --git a/src/applications/uiexample/examples/PHUIIconExample.php b/src/applications/uiexample/examples/PHUIIconExample.php index 2644672a1b..28d957b460 100644 --- a/src/applications/uiexample/examples/PHUIIconExample.php +++ b/src/applications/uiexample/examples/PHUIIconExample.php @@ -110,6 +110,26 @@ final class PHUIIconExample extends PhabricatorUIExample { ->addClass(PHUI::MARGIN_SMALL_RIGHT); } + $circles = array('fa-pencil', 'fa-chevron-left', 'fa-chevron-right'); + $circleview = array(); + foreach ($circles as $circle) { + $circleview[] = + id(new PHUIIconCircleView()) + ->setIconFont($circle) + ->setHref('#') + ->addClass('mmr'); + } + + $circles = array('fa-plus', 'fa-bars', 'fa-paw'); + foreach ($circles as $circle) { + $circleview[] = + id(new PHUIIconCircleView()) + ->setIconFont($circle) + ->setSize(PHUIIconCircleView::MEDIUM) + ->setHref('#') + ->addClass('mmr'); + } + $layout_cicons = id(new PHUIBoxView()) ->appendChild($cicons) ->addMargin(PHUI::MARGIN_LARGE); @@ -130,6 +150,10 @@ final class PHUIIconExample extends PhabricatorUIExample { ->appendChild($tokenview) ->addMargin(PHUI::MARGIN_MEDIUM); + $layout4 = id(new PHUIBoxView()) + ->appendChild($circleview) + ->addMargin(PHUI::MARGIN_MEDIUM); + $layout5 = id(new PHUIBoxView()) ->appendChild($loginview) ->addMargin(PHUI::MARGIN_MEDIUM); @@ -158,6 +182,10 @@ final class PHUIIconExample extends PhabricatorUIExample { ->setHeaderText(pht('Tokens')) ->appendChild($layout3); + $wrap4 = id(new PHUIObjectBoxView()) + ->setHeaderText(pht('Circles')) + ->appendChild($layout4); + $wrap5 = id(new PHUIObjectBoxView()) ->setHeaderText(pht('Authentication')) ->appendChild($layout5); @@ -172,6 +200,7 @@ final class PHUIIconExample extends PhabricatorUIExample { $transforms, $wrap2, $wrap3, + $wrap4, $wrap5, )); } diff --git a/src/docs/user/userguide/profile_menu.diviner b/src/docs/user/userguide/profile_menu.diviner new file mode 100644 index 0000000000..51912dd860 --- /dev/null +++ b/src/docs/user/userguide/profile_menu.diviner @@ -0,0 +1,143 @@ +@title Profile Menu User Guide +@group userguide + +Master profile menus for projects and other objects. + +Overview +======== + +Some objects, like projects, have customizable menus called "profile menus". +This guide discusses how to add, remove, reorder, configure and extend these +menus. + + +Supported Applications +====================== + +These applications currently support profile menus: + +| Application | Support | +|-----|-----| +| Projects | Full | +| People | //Read-Only// | + + +Collapsing and Expanding +======================== + +To collapse a full-width profile menu, click +{nav icon="angle-left", name="Collapse"}. To expand a narrow menu, click +{nav icon="angle-right", name="Expand"}. + +If you're logged in, this setting is sticky, and all menus will respect your +preference. + + +Editing Menus +============= + +You can only edit an object's menu if you can edit the object. For example, you +must have permission to edit a project in order to reconfigure the menu for the +project. + +To edit a menu, click {nav icon="pencil", name="Edit Menu"}. This brings you to +the menu configuration interface which allows you to add and remove items, +reorder the menu, edit existing items, and choose a default item. + +Menus are comprised of a list of items. Some of the items are builtin +(for example, projects have builtin "Profile", "Workboard" and "Members" +items). You can also add custom items. Builtin and custom items mostly +behave in similar ways, but there are a few exceptions (for example, you can +not completely delete builtin items). + + +Adding Items +============ + +To add new items to a menu, use {nav icon="cog", name="Configure Menu"} and +choose a type of item to add. See below for more details on available items. + +You can also find a link to this documentation in the same menu, if you want +to reference it later. + + +Reordering Items +================ + +To reorder items, drag and drop them to the desired position. Your changes +will be reflected in the item ordering in the menu. + + +Setting a Default +================= + +The default item controls what content is shown when a user browses to the +object's main page. For example, the default item for a project controls where +the user ends up when they click a link to the project from another +application. + +To choose a default item, click {nav icon="thumb-tack", name="Make Default"}. +Not all kinds of items can be set as the default item. For example, you can not +set a separator line as a default because the item can't be selected and has no +content. + +If no default is explicitly selected, or a default is deleted or disabled, the +first item which is eligible to be a default is used as the default item. + + +Removing Items +============== + +To remove items, click the {nav icon="times", name="Delete"} action. + +Builtin items can not be deleted and have a +{nav icon="times", name="Disable"} action instead, which will hide them but +not delete them. You an re-enable a disabled item with the +{nav icon="plus', name="Enable"} action. + +Removing or hiding an item does not disable the underlying functionality. +For example, if you hide the "Members" item for a project, that just removes +it from the menu. The project still has members, and users can still navigate +to the members page by following a link to it from elsewhere in the application +or entering the URI manually. + + +Editing Items +============= + +To edit an item, click the name of the item. This will show you available +configuration for the item and allow you to edit it. + +Which properties are editable depends on what sort of item you are editing. +Most items can be renamed, and some items have more settings available. For +example, when editing a link, you can choose the link target and select an +icon for the item. + +A few items have no configuration. For example, visual separator lines are +purely cosmetic and have no available settings. + + +Available Items +=============== + +When you add items, you can choose between different types of items to add. +Which item types are available depends on what sort of object you are editing +the menu for, but most objects support these items: + + - {icon link} **Link**: Allows you to create an item which links to + somewhere else in Phabricator, or to an external site. + - {icon minus} **Divider**: Adds a visual separator to the menu. This is + purely cosmetic. + - {icon coffee} **Motivator**: Motivate your employees with inspirational + quotes. A new quote every day! + +To learn more about how an item works, try adding it. You can always delete +it later if it doesn't do what you wanted. + + +Writing New Item Types +====================== + +IMPORTANT: This feature is not stable, and the API is subject to change. + +To add new types of items, subclass @{class:PhabricatorProfilePanel}. diff --git a/src/docs/user/userguide/projects.diviner b/src/docs/user/userguide/projects.diviner new file mode 100644 index 0000000000..17e8473131 --- /dev/null +++ b/src/docs/user/userguide/projects.diviner @@ -0,0 +1,95 @@ +@title Projects User Guide +@group userguide + +Organize users and objects with projects. + +Overview +======== + +NOTE: This document is only partially complete. + +Phabricator projects are flexible groups of users and objects. + + +Joining Projects +================ + +Once you join a project, you become a member and will receive mail sent to the +project, like a mailing list. For example, if a project is added as a +subscriber on a task or a reviewer on a revision, you will receive mail about +that task or revision. + +If you'd prefer not to receive mail sent to a project, you can go to +{nav Members} and select {nav Disable Mail}. If you disable mail for a project, +you will no longer receive mail sent to the project. + + +Watching Projects +================= + +Watching a project allows you to closely follow all activity related to a +project. + +You can **watch** a project by clicking {nav Watch Project} on the project +page. To stop watching a project, click {nav Unwatch Project}. + +When you watch a project, you will receive a copy of mail about any objects +(like tasks or revisions) that are tagged with the project, or that the project +is a subscriber, reviewer, or auditor for. For moderately active projects, this +may be a large volume of mail. + + +Edit Notifications +================== + +Edit notifications are generated when project details (like the project +description, name, or icon) are updated, or when users join or leave projects. + +By default, these notifications are are only sent to the acting user. These +notifications are usually not very interesting, and project mail is already +complicated by members and watchers. + +If you'd like to receive edit notifications for a project, you can write a +Herald rule to keep you in the loop. + + +Customizing Menus +================= + +Projects support profile menus, which are customizable. For full details on +managing and customizing profile menus, see @{article:Profile Menu User Guide}. + +Here are some examples of common ways to customize project profile menus that +may be useful: + +**Link to Tasks or Repositories**: You can add a menu item for "Open Tasks" or +"Active Repositories" for a project by running the search in the appropriate +application, then adding a link to the search results to the menu. + +This can let you quickly jump from a project screen to related tasks, +revisions, repositories, or other objects. + +For more details on how to use search and manage queries, see +@{article:Search User Guide}. + +**New Task Button**: To let users easily make a new task that is tagged with +the current project, add a link to the "New Task" form with the project +prefilled, or to a custom form with appropriate defaults. + +For information on customizing and prefilling forms, see +@{article:User Guide: Customizing Forms}. + +**Link to Wiki Pages**: You can add links to relevant wiki pages or other +documentation to the menu to make it easy to find and access. You could also +link to a Conpherence if you have a chatroom for a project. + +**Link to External Resources**: You can link to external resources outside +of Phabricator if you have other pages which are relevant to a project. + +**Set Workboard as Default**: For projects that are mostly used to organize +tasks, change the default item to the workboard instead of the profile to get +to the workboard view more easily. + +**Hide Unused Items**: If you have a project which you don't expect to have +members or won't have a workboard, you can hide these items to streamline the +menu. diff --git a/src/infrastructure/daemon/workers/storage/PhabricatorWorkerBulkJob.php b/src/infrastructure/daemon/workers/storage/PhabricatorWorkerBulkJob.php index 20d981c576..0b70268cb4 100644 --- a/src/infrastructure/daemon/workers/storage/PhabricatorWorkerBulkJob.php +++ b/src/infrastructure/daemon/workers/storage/PhabricatorWorkerBulkJob.php @@ -222,10 +222,6 @@ final class PhabricatorWorkerBulkJob return true; } - public function shouldAllowSubscription($phid) { - return true; - } - /* -( PhabricatorApplicationTransactionInterface )------------------------- */ diff --git a/src/infrastructure/markup/view/PHUIRemarkupView.php b/src/infrastructure/markup/view/PHUIRemarkupView.php index 0272c9c3a9..8a11653589 100644 --- a/src/infrastructure/markup/view/PHUIRemarkupView.php +++ b/src/infrastructure/markup/view/PHUIRemarkupView.php @@ -24,6 +24,7 @@ final class PHUIRemarkupView extends AphrontView { return PhabricatorMarkupEngine::renderOneObject( id(new PhabricatorMarkupOneOff()) + ->setPreserveLinebreaks(true) ->setContent($corpus), 'default', $viewer); diff --git a/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php b/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php index 1892e53e7c..0efca33b6a 100644 --- a/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php +++ b/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php @@ -381,6 +381,12 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery $column = $orderable[$key]; $column['value'] = $value_map[$key]; + // If the vector component is reversed, we need to reverse whatever the + // order of the column is. + if ($order->getIsReversed()) { + $column['reverse'] = !idx($column, 'reverse', false); + } + $columns[] = $column; } diff --git a/src/infrastructure/storage/management/PhabricatorStorageManagementAPI.php b/src/infrastructure/storage/management/PhabricatorStorageManagementAPI.php index 76e8e0a057..87cb079c7e 100644 --- a/src/infrastructure/storage/management/PhabricatorStorageManagementAPI.php +++ b/src/infrastructure/storage/management/PhabricatorStorageManagementAPI.php @@ -123,6 +123,16 @@ final class PhabricatorStorageManagementAPI extends Phobject { 'SELECT patch FROM %T', self::TABLE_STATUS); return ipull($applied, 'patch'); + } catch (AphrontAccessDeniedQueryException $ex) { + throw new PhutilProxyException( + pht( + 'Failed while trying to read schema status: the database "%s" '. + 'exists, but the current user ("%s") does not have permission to '. + 'access it. GRANT the current user more permissions, or use a '. + 'different user.', + $this->getDatabaseName('meta_data'), + $this->getUser()), + $ex); } catch (AphrontQueryException $ex) { return null; } @@ -246,10 +256,19 @@ final class PhabricatorStorageManagementAPI extends Phobject { $query = str_replace('{$'.$key.'}', $value, $query); } - queryfx( - $conn, - '%Q', - $query); + try { + queryfx($conn, '%Q', $query); + } catch (AphrontAccessDeniedQueryException $ex) { + throw new PhutilProxyException( + pht( + 'Unable to access a required database or table. This almost '. + 'always means that the user you are connecting with ("%s") does '. + 'not have sufficient permissions granted in MySQL. You can '. + 'use `bin/storage databases` to get a list of all databases '. + 'permission is required on.', + $this->getUser()), + $ex); + } } } diff --git a/src/infrastructure/storage/management/workflow/PhabricatorStorageManagementWorkflow.php b/src/infrastructure/storage/management/workflow/PhabricatorStorageManagementWorkflow.php index cbb88ce818..cc917215ee 100644 --- a/src/infrastructure/storage/management/workflow/PhabricatorStorageManagementWorkflow.php +++ b/src/infrastructure/storage/management/workflow/PhabricatorStorageManagementWorkflow.php @@ -422,6 +422,11 @@ abstract class PhabricatorStorageManagementWorkflow continue; } + if ($actual_database->getAccessDenied()) { + // If we can't access the database, we can't access the tables either. + continue; + } + $issues = array(); if ($database->hasIssue($issue_charset)) { $issues[] = $issue_charset; @@ -634,6 +639,8 @@ abstract class PhabricatorStorageManagementWorkflow $any_surplus = false; $all_surplus = true; + $any_access = false; + $all_access = true; foreach ($errors as $error) { $pieces = array_select_keys( $error, @@ -643,12 +650,20 @@ abstract class PhabricatorStorageManagementWorkflow $name = PhabricatorConfigStorageSchema::getIssueName($error['issue']); - if ($error['issue'] === PhabricatorConfigStorageSchema::ISSUE_SURPLUS) { + $issue = $error['issue']; + + if ($issue === PhabricatorConfigStorageSchema::ISSUE_SURPLUS) { $any_surplus = true; } else { $all_surplus = false; } + if ($issue === PhabricatorConfigStorageSchema::ISSUE_ACCESSDENIED) { + $any_access = true; + } else { + $all_access = false; + } + $table->addRow( array( 'target' => $target, @@ -668,11 +683,24 @@ abstract class PhabricatorStorageManagementWorkflow 'does not expect). For information on resolving these '. 'issues, see the "Surplus Schemata" section in the "Managing Storage '. 'Adjustments" article in the documentation.'); + } else if ($all_access) { + $message[] = pht( + 'The user you are connecting to MySQL with does not have the correct '. + 'permissions, and can not access some databases or tables that it '. + 'needs to be able to access. GRANT the user additional permissions.'); } else { $message[] = pht( 'The schemata have errors (detailed above) which the adjustment '. 'workflow can not fix.'); + if ($any_access) { + $message[] = pht( + 'Some of these errors are caused by access control problems. '. + 'The user you are connecting with does not have permission to see '. + 'all of the database or tables that Phabricator uses. You need to '. + 'GRANT the user more permission, or use a different user.'); + } + if ($any_surplus) { $message[] = pht( 'Some of these errors are caused by surplus schemata (extra '. @@ -698,6 +726,11 @@ abstract class PhabricatorStorageManagementWorkflow "** %s **\n\n%s\n", pht('SURPLUS SCHEMATA'), phutil_console_wrap($message)); + } else if ($all_access) { + $console->writeOut( + "** %s **\n\n%s\n", + pht('ACCESS DENIED'), + phutil_console_wrap($message)); } else { $console->writeOut( "** %s **\n\n%s\n", diff --git a/src/view/form/control/PhabricatorRemarkupControl.php b/src/view/form/control/PhabricatorRemarkupControl.php index be989d8a5c..11388d257e 100644 --- a/src/view/form/control/PhabricatorRemarkupControl.php +++ b/src/view/form/control/PhabricatorRemarkupControl.php @@ -44,6 +44,9 @@ final class PhabricatorRemarkupControl extends AphrontFormTextAreaControl { $root_id = celerity_generate_unique_node_id(); + $user_datasource = new PhabricatorPeopleDatasource(); + $proj_datasource = new PhabricatorProjectDatasource(); + Javelin::initBehavior( 'phabricator-remarkup-assist', array( @@ -59,6 +62,20 @@ final class PhabricatorRemarkupControl extends AphrontFormTextAreaControl { ), 'disabled' => $this->getDisabled(), 'rootID' => $root_id, + 'autocompleteMap' => (object)array( + 64 => array( // "@" + 'datasourceURI' => $user_datasource->getDatasourceURI(), + 'headerIcon' => 'fa-user', + 'headerText' => pht('Find User:'), + 'hintText' => $user_datasource->getPlaceholderText(), + ), + 35 => array( // "#" + 'datasourceURI' => $proj_datasource->getDatasourceURI(), + 'headerIcon' => 'fa-briefcase', + 'headerText' => pht('Find Project:'), + 'hintText' => $proj_datasource->getPlaceholderText(), + ), + ), )); Javelin::initBehavior('phabricator-tooltips', array()); diff --git a/src/view/layout/AphrontSideNavFilterView.php b/src/view/layout/AphrontSideNavFilterView.php index 45e49f43fe..3a267510f0 100644 --- a/src/view/layout/AphrontSideNavFilterView.php +++ b/src/view/layout/AphrontSideNavFilterView.php @@ -27,12 +27,15 @@ final class AphrontSideNavFilterView extends AphrontView { private $crumbs; private $classes = array(); private $menuID; - private $iconNav; + private $mainID; + private $isProfileMenu; + private $footer = array(); public function setMenuID($menu_id) { $this->menuID = $menu_id; return $this; } + public function getMenuID() { return $this->menuID; } @@ -55,11 +58,15 @@ final class AphrontSideNavFilterView extends AphrontView { return $this->crumbs; } - public function setIconNav($nav) { - $this->iconNav = $nav; + public function setIsProfileMenu($is_profile) { + $this->isProfileMenu = $is_profile; return $this; } + public function getIsProfileMenu() { + return $this->isProfileMenu; + } + public function setActive($active) { $this->active = $active; return $this; @@ -93,26 +100,6 @@ final class AphrontSideNavFilterView extends AphrontView { $key, $name, $uri, PHUIListItemView::TYPE_LINK); } - public function addIcon($key, $name, $icon, $image = null, $uri = null) { - if (!$uri) { - $href = clone $this->baseURI; - $href->setPath(rtrim($href->getPath().$key, '/').'/'); - $href = (string)$href; - } else { - $href = $uri; - } - - $item = id(new PHUIListItemView()) - ->setKey($key) - ->setRenderNameAsTooltip(true) - ->setType(PHUIListItemView::TYPE_ICON_NAV) - ->setIcon($icon) - ->setHref($href) - ->setName($name) - ->setProfileImage($image); - return $this->addMenuItem($item); - } - public function addButton($key, $name, $uri = null) { return $this->addThing( $key, $name, $uri, PHUIListItemView::TYPE_BUTTON); @@ -177,6 +164,18 @@ final class AphrontSideNavFilterView extends AphrontView { return $this->selectedFilter; } + public function appendFooter($footer) { + $this->footer[] = $footer; + return $this; + } + + public function getMainID() { + if (!$this->mainID) { + $this->mainID = celerity_generate_unique_node_id(); + } + return $this->mainID; + } + public function render() { if ($this->menu->getItems()) { if (!$this->baseURI) { @@ -207,8 +206,12 @@ final class AphrontSideNavFilterView extends AphrontView { $nav_classes = array(); $nav_classes[] = 'phabricator-nav'; - if ($this->iconNav) { - $nav_classes[] = 'phabricator-icon-nav'; + + if ($this->getIsProfileMenu()) { + require_celerity_resource('phui-profile-menu-css'); + // No class, we're going to put it on the shell instead. + } else { + $nav_classes[] = 'phabricator-basic-nav'; } $nav_id = null; @@ -217,7 +220,7 @@ final class AphrontSideNavFilterView extends AphrontView { $local_id = null; $background_id = null; $local_menu = null; - $main_id = celerity_generate_unique_node_id(); + $main_id = $this->getMainID(); if ($this->flexible) { $drag_id = celerity_generate_unique_node_id(); @@ -284,7 +287,17 @@ final class AphrontSideNavFilterView extends AphrontView { $nav_classes = array_merge($nav_classes, $this->classes); - return phutil_tag( + $footer = $this->footer; + + if ($this->getIsProfileMenu()) { + $internal_footer = $footer; + $external_footer = null; + } else { + $internal_footer = null; + $external_footer = $footer; + } + + $menu = phutil_tag( 'div', array( 'class' => implode(' ', $nav_classes), @@ -302,8 +315,27 @@ final class AphrontSideNavFilterView extends AphrontView { array( $crumbs, $this->renderChildren(), + $internal_footer, )), )); + + if ($this->getIsProfileMenu()) { + $shell = phutil_tag( + 'div', + array( + 'class' => 'phui-navigation-shell phui-profile-menu', + ), + array( + $menu, + )); + } else { + $shell = array( + $menu, + $external_footer, + ); + } + + return $shell; } } diff --git a/src/view/layout/PHUIApplicationMenuView.php b/src/view/layout/PHUIApplicationMenuView.php index f542674de9..164f897550 100644 --- a/src/view/layout/PHUIApplicationMenuView.php +++ b/src/view/layout/PHUIApplicationMenuView.php @@ -75,8 +75,11 @@ final class PHUIApplicationMenuView extends Phobject { $profile_menu = $this->getProfileMenu(); if ($profile_menu) { foreach ($profile_menu->getMenu()->getItems() as $item) { + if ($item->getHideInApplicationMenu()) { + continue; + } + $item = clone $item; - $item->setRenderNameAsTooltip(false); $view->addMenuItem($item); } } diff --git a/src/view/page/PhabricatorStandardPageView.php b/src/view/page/PhabricatorStandardPageView.php index 3b1c38962b..b26ce6297b 100644 --- a/src/view/page/PhabricatorStandardPageView.php +++ b/src/view/page/PhabricatorStandardPageView.php @@ -478,6 +478,8 @@ final class PhabricatorStandardPageView extends PhabricatorBarePageView $body = parent::getBody(); + $footer = $this->renderFooter(); + $nav = $this->getNavigation(); if ($nav) { $crumbs = $this->getCrumbs(); @@ -485,18 +487,25 @@ final class PhabricatorStandardPageView extends PhabricatorBarePageView $nav->setCrumbs($crumbs); } $nav->appendChild($body); - $body = phutil_implode_html('', array($nav->render())); + $nav->appendFooter($footer); + $content = phutil_implode_html('', array($nav->render())); } else { + $contnet = array(); + $crumbs = $this->getCrumbs(); if ($crumbs) { - $body = phutil_implode_html('', array($crumbs, $body)); + $content[] = $crumbs; } + + $content[] = $body; + $content[] = $footer; + + $content = phutil_implode_html('', $content); } return array( ($console ? hsprintf('') : null), - $body, - $this->renderFooter(), + $content, ); } diff --git a/src/view/page/menu/PhabricatorMainMenuView.php b/src/view/page/menu/PhabricatorMainMenuView.php index 54ba622f80..5ce25fb3da 100644 --- a/src/view/page/menu/PhabricatorMainMenuView.php +++ b/src/view/page/menu/PhabricatorMainMenuView.php @@ -27,7 +27,6 @@ final class PhabricatorMainMenuView extends AphrontView { $user = $this->user; require_celerity_resource('phabricator-main-menu-view'); - require_celerity_resource('sprite-main-header-css'); $header_id = celerity_generate_unique_node_id(); $menu_bar = array(); @@ -137,7 +136,7 @@ final class PhabricatorMainMenuView extends AphrontView { $application_menu = $this->renderApplicationMenu($bar_items); $classes = array(); - $classes[] = 'phabricator-main-menu sprite-main-header'; + $classes[] = 'phabricator-main-menu'; $classes[] = 'phabricator-main-menu-background'; return phutil_tag( diff --git a/src/view/phui/PHUIBoxView.php b/src/view/phui/PHUIBoxView.php index bc805515f0..7068f8811c 100644 --- a/src/view/phui/PHUIBoxView.php +++ b/src/view/phui/PHUIBoxView.php @@ -5,6 +5,10 @@ final class PHUIBoxView extends AphrontTagView { private $margin = array(); private $padding = array(); private $border = false; + private $color; + + const BLUE = 'phui-box-blue'; + const GREY = 'phui-box-grey'; public function addMargin($margin) { $this->margin[] = $margin; @@ -21,19 +25,32 @@ final class PHUIBoxView extends AphrontTagView { return $this; } + public function setColor($color) { + $this->color = $color; + return $this; + } + protected function getTagAttributes() { require_celerity_resource('phui-box-css'); $outer_classes = array(); $outer_classes[] = 'phui-box'; + if ($this->border) { $outer_classes[] = 'phui-box-border'; } + foreach ($this->margin as $margin) { $outer_classes[] = $margin; } + foreach ($this->padding as $padding) { $outer_classes[] = $padding; } + + if ($this->color) { + $outer_classes[] = $this->color; + } + return array('class' => $outer_classes); } diff --git a/src/view/phui/PHUIIconCircleView.php b/src/view/phui/PHUIIconCircleView.php new file mode 100644 index 0000000000..1269c4e28c --- /dev/null +++ b/src/view/phui/PHUIIconCircleView.php @@ -0,0 +1,67 @@ +href = $href; + return $this; + } + + public function setIconFont($icon) { + $this->icon = $icon; + return $this; + } + + public function setColor($color) { + $this->color = $color; + return $this; + } + + public function setSize($size) { + $this->size = $size; + return $this; + } + + protected function getTagName() { + $tag = 'span'; + if ($this->href) { + $tag = 'a'; + } + return $tag; + } + + protected function getTagAttributes() { + require_celerity_resource('phui-icon-view-css'); + + $classes = array(); + $classes[] = 'phui-icon-circle'; + + if ($this->color) { + $classes[] = 'phui-icon-circle-'.$this->color; + } + + if ($this->size) { + $classes[] = $this->size; + } + + return array( + 'href' => $this->href, + 'class' => $classes, + ); + } + + protected function getTagContent() { + return id(new PHUIIconView()) + ->setIconFont($this->icon) + ->addClass($this->color); + } + +} diff --git a/src/view/phui/PHUIIconView.php b/src/view/phui/PHUIIconView.php index c9d8a0808e..c383aff30b 100644 --- a/src/view/phui/PHUIIconView.php +++ b/src/view/phui/PHUIIconView.php @@ -4,7 +4,6 @@ final class PHUIIconView extends AphrontTagView { const SPRITE_TOKENS = 'tokens'; const SPRITE_LOGIN = 'login'; - const SPRITE_PROJECTS = 'projects'; const HEAD_SMALL = 'phuihead-small'; const HEAD_MEDIUM = 'phuihead-medium'; diff --git a/src/view/phui/PHUIListItemView.php b/src/view/phui/PHUIListItemView.php index e877049840..f0bb46fb87 100644 --- a/src/view/phui/PHUIListItemView.php +++ b/src/view/phui/PHUIListItemView.php @@ -9,7 +9,6 @@ final class PHUIListItemView extends AphrontTagView { const TYPE_CUSTOM = 'type-custom'; const TYPE_DIVIDER = 'type-divider'; const TYPE_ICON = 'type-icon'; - const TYPE_ICON_NAV = 'type-icon-nav'; const STATUS_WARN = 'phui-list-item-warn'; const STATUS_FAIL = 'phui-list-item-fail'; @@ -20,7 +19,6 @@ final class PHUIListItemView extends AphrontTagView { private $isExternal; private $key; private $icon; - private $appIcon; private $selected; private $disabled; private $renderNameAsTooltip; @@ -29,6 +27,17 @@ final class PHUIListItemView extends AphrontTagView { private $aural; private $profileImage; private $indented; + private $hideInApplicationMenu; + private $icons = array(); + + public function setHideInApplicationMenu($hide) { + $this->hideInApplicationMenu = $hide; + return $this; + } + + public function getHideInApplicationMenu() { + return $this->hideInApplicationMenu; + } public function setDropdownMenu(PhabricatorActionListView $actions) { Javelin::initBehavior('phui-dropdown-menu'); @@ -151,6 +160,15 @@ final class PHUIListItemView extends AphrontTagView { return $this; } + public function addIcon($icon) { + $this->icons[] = $icon; + return $this; + } + + public function getIcons() { + return $this->icons; + } + protected function getTagName() { return 'li'; } @@ -160,7 +178,7 @@ final class PHUIListItemView extends AphrontTagView { $classes[] = 'phui-list-item-view'; $classes[] = 'phui-list-item-'.$this->type; - if ($this->icon || $this->appIcon) { + if ($this->icon) { $classes[] = 'phui-list-item-has-icon'; } @@ -257,13 +275,8 @@ final class PHUIListItemView extends AphrontTagView { if ($this->profileImage) { $icon = id(new PHUIIconView()) ->setHeadSize(PHUIIconView::HEAD_SMALL) - ->setImage($this->profileImage); - } - - if ($this->appIcon) { - $icon = id(new PHUIIconView()) ->addClass('phui-list-item-icon') - ->setIconFont($this->appIcon); + ->setImage($this->profileImage); } $classes = array(); @@ -275,6 +288,8 @@ final class PHUIListItemView extends AphrontTagView { $classes[] = 'phui-list-item-indented'; } + $icons = $this->getIcons(); + return javelin_tag( $this->href ? 'a' : 'div', array( @@ -286,6 +301,7 @@ final class PHUIListItemView extends AphrontTagView { array( $aural, $icon, + $icons, $this->renderChildren(), $name, )); diff --git a/src/view/phui/PHUIStatusItemView.php b/src/view/phui/PHUIStatusItemView.php index f4cfaf4462..b268360eef 100644 --- a/src/view/phui/PHUIStatusItemView.php +++ b/src/view/phui/PHUIStatusItemView.php @@ -24,7 +24,6 @@ final class PHUIStatusItemView extends AphrontTagView { const ICON_CLOCK = 'fa-clock-o'; const ICON_STAR = 'fa-star'; - /* render_textarea */ public function setIcon($icon, $color = null, $label = null) { $this->icon = $icon; $this->iconLabel = $label; diff --git a/webroot/rsrc/css/application/base/main-menu-view.css b/webroot/rsrc/css/application/base/main-menu-view.css index b70e0b7470..92385e6dc2 100644 --- a/webroot/rsrc/css/application/base/main-menu-view.css +++ b/webroot/rsrc/css/application/base/main-menu-view.css @@ -16,13 +16,11 @@ } .phabricator-main-menu-background { - min-height: 43px; - background-color: #ebecee; - border-bottom: 1px solid rgba(0,0,0,.1); + min-height: 44px; } .device-desktop .phabricator-main-menu { - height: 43px; + height: 44px; padding-right: 4px; } diff --git a/webroot/rsrc/css/application/base/phui-theme.css b/webroot/rsrc/css/application/base/phui-theme.css index 1d3d9210bd..03ccb8f38e 100644 --- a/webroot/rsrc/css/application/base/phui-theme.css +++ b/webroot/rsrc/css/application/base/phui-theme.css @@ -2,11 +2,39 @@ * @provides phui-theme-css */ - .phui-theme-light button.phabricator-main-menu-search-dropdown .caret:before { +/*--- Base Colors ------------------------------------------------------------*/ + +.phui-theme-blindigo .phabricator-main-menu-background { + background: #41506e; +} + +.phui-theme-dark .phabricator-main-menu-background { + background: #171c20; +} + +.phui-theme-indigo .phabricator-main-menu-background { + background: #4a2b85; +} + +.phui-theme-red .phabricator-main-menu-background { + background: #650404; +} + +.phui-theme-blue .phabricator-main-menu-background { + background: #004377; +} + +.phui-theme-green .phabricator-main-menu-background { + background: #124A1B; +} + +/*--- Light Colors -----------------------------------------------------------*/ + +.phui-theme-light button.phabricator-main-menu-search-dropdown .caret:before { color: {$lightbluetext}; } - .phui-theme-light .phabricator-main-menu-search +.phui-theme-light .phabricator-main-menu-search button.phabricator-main-menu-search-dropdown .phui-icon-view { color: {$lightbluetext}; text-shadow: {$whitetextshadow}; diff --git a/webroot/rsrc/css/application/base/standard-page-view.css b/webroot/rsrc/css/application/base/standard-page-view.css index 9670ddd7ae..830554db3e 100644 --- a/webroot/rsrc/css/application/base/standard-page-view.css +++ b/webroot/rsrc/css/application/base/standard-page-view.css @@ -37,10 +37,6 @@ margin-left: 221px; } -.device-desktop div.phabricator-icon-nav + .phabricator-standard-page-footer { - margin-left: 58px; -} - .device .phabricator-side-menu-home + .phabricator-standard-page-footer { display: none; } diff --git a/webroot/rsrc/css/application/people/people-profile.css b/webroot/rsrc/css/application/people/people-profile.css index 089402b4d7..d73b94fb97 100644 --- a/webroot/rsrc/css/application/people/people-profile.css +++ b/webroot/rsrc/css/application/people/people-profile.css @@ -37,6 +37,14 @@ form.compose-dialog { background-color: {$darkgreytext}; } +.compose-dialog .compose-icon-bg { + color: rgba(255,255,255,0.8); + line-height: 50px; + width: 50px; + text-align: center; + font-size: 32px; +} + .compose-dialog .compose-background-red { background-color: {$red}; } diff --git a/webroot/rsrc/css/application/phame/phame.css b/webroot/rsrc/css/application/phame/phame.css index 65604a6dd6..be161c1ede 100644 --- a/webroot/rsrc/css/application/phame/phame.css +++ b/webroot/rsrc/css/application/phame/phame.css @@ -49,17 +49,14 @@ .phame-blog-list { margin: 24px 16px 16px 16px; - padding: 16px; - background-color: {$bluebackground}; - border-radius: 3px; } .device .phame-blog-list { - padding: 16px 8px; - background-color: #F1F1F4; + padding: 0; + background-color: {$bluebackground}; margin: 0; border-radius: 0; - border-bottom: 1px solid {$lightblueborder}; + border-bottom: 1px solid {$thinblueborder}; } .phame-blog-list-item:last-child { diff --git a/webroot/rsrc/css/core/remarkup.css b/webroot/rsrc/css/core/remarkup.css index 6c43ba6159..bec9c3e29e 100644 --- a/webroot/rsrc/css/core/remarkup.css +++ b/webroot/rsrc/css/core/remarkup.css @@ -561,3 +561,58 @@ var.remarkup-assist-textarea { .device .remarkup-assist-nodevice { display: none; } + +.phuix-autocomplete { + position: absolute; + width: 300px; + box-shadow: {$dropshadow}; + background: #ffffff; + border: 1px solid {$lightgreyborder}; + border-radius: 3px; +} + +.phuix-autocomplete-head { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + padding: 6px 8px; + background: {$lightgreybackground}; + color: {$darkgreytext}; + border-radius: 3px; +} + +.phuix-autocomplete-head .phui-icon-view { + margin-right: 4px; + color: {$lightgreytext}; +} + +.phuix-autocomplete-echo { + margin-left: 4px; + color: {$lightgreytext}; +} + +.phuix-autocomplete-list a.jx-result { + display: block; + padding: 5px 8px; + font-size: {$normalfontsize}; + border-top: 1px solid {$thinblueborder}; + font-weight: bold; + color: {$darkgreytext}; +} + +.phuix-autocomplete-list a.jx-result .phui-icon-view { + margin-right: 4px; + color: {$lightbluetext}; +} + +.phuix-autocomplete-list a.jx-result:hover { + text-decoration: none; + background: {$sh-bluebackground}; + color: #000; +} + +.phuix-autocomplete-list a.jx-result.focused, +.phuix-autocomplete-list a.jx-result.focused:hover { + background: {$sh-bluebackground}; + color: #000; +} diff --git a/webroot/rsrc/css/core/z-index.css b/webroot/rsrc/css/core/z-index.css index 06513c9d59..3025b5dc5c 100644 --- a/webroot/rsrc/css/core/z-index.css +++ b/webroot/rsrc/css/core/z-index.css @@ -150,6 +150,10 @@ div.jx-typeahead-results { z-index: 20; } +.phuix-autocomplete { + z-index: 21; +} + .phuix-dropdown-menu { z-index: 32; } diff --git a/webroot/rsrc/css/layout/phabricator-side-menu-view.css b/webroot/rsrc/css/layout/phabricator-side-menu-view.css index 7f0d2bc720..5b425c2a5f 100644 --- a/webroot/rsrc/css/layout/phabricator-side-menu-view.css +++ b/webroot/rsrc/css/layout/phabricator-side-menu-view.css @@ -2,7 +2,7 @@ * @provides phabricator-side-menu-view-css */ -.phabricator-side-menu .phui-list-item-view { +.phabricator-basic-nav .phabricator-side-menu .phui-list-item-view { display: block; white-space: nowrap; text-decoration: none; @@ -10,7 +10,7 @@ -webkit-font-smoothing: antialiased; } -.phabricator-side-menu .phui-list-item-href { +.phabricator-basic-nav .phabricator-side-menu .phui-list-item-href { display: block; padding: 6px 8px 6px 24px; color: {$darkbluetext}; @@ -18,7 +18,7 @@ border-bottom-right-radius: 3px; } -.phabricator-side-menu .phui-list-item-selected { +.phabricator-basic-nav .phabricator-side-menu .phui-list-item-selected { background-color: rgba(0,0,0,.05); border-left: 4px solid {$sky}; border-top-right-radius: 3px; @@ -26,20 +26,18 @@ font-weight: bold; } -.phabricator-icon-nav .phabricator-side-menu .phui-list-item-selected { - background-color: rgba(0,0,0,.1); -} - -.device-desktop .phabricator-side-menu .phui-list-item-selected +.device-desktop .phabricator-basic-nav .phabricator-side-menu + .phui-list-item-selected a.phui-list-item-href:hover { background-color: rgba(0,0,0,.05); } -.phabricator-side-menu .phui-list-item-selected .phui-list-item-href { +.phabricator-basic-nav .phabricator-side-menu .phui-list-item-selected + .phui-list-item-href { padding-left: 20px; } -.phabricator-side-menu .phui-list-item-type-label { +.phabricator-basic-nav .phabricator-side-menu .phui-list-item-type-label { padding: 6px 8px 4px 12px; color: {$darkbluetext}; text-transform: uppercase; @@ -48,65 +46,8 @@ border-style: solid; } -.device-desktop .phabricator-side-menu a.phui-list-item-href:hover { +.device-desktop .phabricator-basic-nav .phabricator-side-menu + a.phui-list-item-href:hover { text-decoration: none; background-color: rgba(0,0,0,.07); } - -.device-desktop .phabricator-icon-nav a.phui-list-item-href:hover - .phui-list-item-icon { - color: {$darkbluetext}; - } - -.device-desktop .phabricator-icon-nav .phabricator-nav-local { - width: 40px; - margin-top: 16px; - border-color: {$lightblueborder}; - border-width: 1px 1px 1px 0; - border-style: solid; - background-color: #fff; - border-top-right-radius: 3px; - border-bottom-right-radius: 3px; -} - -.device-desktop .phabricator-icon-nav .phabricator-nav-content { - margin-left: 41px; -} - -.phabricator-icon-nav .phabricator-side-menu .phui-list-item-href { - height: 40px; - width: 40px; - padding: 0; -} - -.phabricator-icon-nav .phabricator-side-menu .phui-list-item-icon { - font-size: 20px; - width: 40px; - line-height: 38px; - text-align: center; - vertical-align: bottom; - text-shadow: {$whitetextshadow}; - color: {$blue}; -} - -.phabricator-icon-nav .phabricator-side-menu .phui-list-item-icon.grey { - color: {$lightgreyborder}; -} - -.phabricator-icon-nav .phabricator-side-menu .phui-list-item-selected { - border: none; -} - -.phabricator-icon-nav .phabricator-side-menu .phui-list-item-selected - .phui-icon-view { - color: {$darkbluetext}; -} - -.phabricator-icon-nav .phui-icon-view.phuihead-small { - height: 24px; - width: 24px; - border: 1px solid #fff; - background-size: 24px; - display: inline-block; - margin: 7px; -} diff --git a/webroot/rsrc/css/phui/phui-box.css b/webroot/rsrc/css/phui/phui-box.css index da9b85e765..e31c4bcae4 100644 --- a/webroot/rsrc/css/phui/phui-box.css +++ b/webroot/rsrc/css/phui/phui-box.css @@ -11,3 +11,13 @@ .phui-box.focus { box-shadow: 0 0 5px 5px rgba(255, 255, 0, 0.90); } + +.phui-box-grey { + background-color: rgba(71,87,120,0.1); + border-radius: 3px; +} + +.phui-box-blue { + background-color: {$bluebackground}; + border-radius: 3px; +} diff --git a/webroot/rsrc/css/phui/phui-icon.css b/webroot/rsrc/css/phui/phui-icon.css index 5df51476d1..ad789768c8 100644 --- a/webroot/rsrc/css/phui/phui-icon.css +++ b/webroot/rsrc/css/phui/phui-icon.css @@ -38,3 +38,45 @@ a.phui-icon-view:hover { text-decoration: none; color: {$sky}; } + +/* - Icon in a Circle ------------------------------------------------------- */ + +.phui-icon-circle { + border: 1px solid {$lightblueborder}; + border-radius: 24px; + height: 24px; + width: 24px; + text-align: center; + display: inline-block; + cursor: pointer; +} + +.phui-icon-circle.circle-medium { + height: 36px; + width: 36px; + border-radius: 36px; +} + +.phui-icon-circle .phui-icon-view { + height: 24px; + width: 24px; + font-size: 11px; + line-height: 24px; + color: {$lightblueborder}; + cursor: pointer; +} + +.phui-icon-circle.circle-medium .phui-icon-view { + font-size: 18px; + line-height: 36px; +} + +a.phui-icon-circle:hover { + text-decoration: none; + border-color: {$sky}; + cursor: pointer; +} + +a.phui-icon-circle:hover .phui-icon-view { + color: {$sky}; +} diff --git a/webroot/rsrc/css/phui/phui-profile-menu.css b/webroot/rsrc/css/phui/phui-profile-menu.css new file mode 100644 index 0000000000..8c765b56f2 --- /dev/null +++ b/webroot/rsrc/css/phui/phui-profile-menu.css @@ -0,0 +1,239 @@ +/** + * @provides phui-profile-menu-css + */ + +.device-desktop .phui-navigation-shell.phui-profile-menu { + display: table; + width: 100%; + height: calc(100vh - {$menu.main.height}); +} + +.device-desktop .phui-profile-menu .phabricator-nav { + display: table-row; +} + +.device-desktop .phui-profile-menu .phabricator-nav-local { + display: table-cell; + position: relative; + vertical-align: top; + width: {$menu.profile.width}; + max-width: {$menu.profile.width}; + transition: .2s; + margin-top: 0; + overflow: hidden; +} + +.device-desktop .phui-profile-menu-collapsed .phabricator-nav-local { + width: {$menu.profile.width.collapsed}; + max-width: {$menu.profile.width.collapsed}; +} + +.device-desktop .phui-profile-menu .phabricator-nav-content { + display: table-cell; + margin-left: 0; +} + +.phui-profile-menu .phabricator-side-menu { + background: {$menu.profile.background}; + box-shadow: inset -2px 0 2px rgba(0, 0, 0, 0.150); + width: 240px; +} + +.phui-profile-menu .phabricator-side-menu .phui-list-item-view { + position: relative; +} + +.phui-profile-menu .phabricator-side-menu .phui-list-item-href { + display: block; + text-decoration: none; + padding: 0 8px 0 48px; + height: 48px; + font-size: {$biggerfontsize}; + -webkit-font-smoothing: antialiased; + color: {$menu.profile.text}; + line-height: 22px; + overflow: hidden; + text-overflow: ellipsis; + line-height: 48px; +} + +.phui-profile-menu .phabricator-side-menu .phui-list-item-icon, +.phui-profile-menu .phabricator-side-menu + .phui-list-item-href .phui-list-item-icon { + position: absolute; + top: 12px; + left: 13px; + font-size: 24px; + width: 24px; + height: 24px; + line-height: 24px; + text-align: center; + color: {$menu.profile.text}; + background-size: 100%; +} + +.phui-profile-menu .phui-profile-menu-collapsed .phabricator-side-menu + .phui-list-item-href { + text-align: center; + padding: 42px 4px 14px; + line-height: 14px; + height: auto; + font-size: {$smallerfontsize}; +} + +.phui-profile-menu .phui-profile-menu-collapsed .phabricator-side-menu + .phui-list-item-name { + display: block; + overflow: hidden; + text-overflow: ellipsis; +} + +.phui-profile-menu .phui-profile-menu-collapsed .phabricator-side-menu + .phui-list-item-icon, +.phui-profile-menu .phui-profile-menu-collapsed .phabricator-side-menu + .phui-list-item-href .phui-list-item-icon { + top: 14px; + left: 32px; +} + +.phui-profile-menu .phabricator-side-menu + .phui-list-item-disabled + .phui-list-item-icon { + color: {$menu.profile.icon.disabled}; +} + +.phui-profile-menu .phabricator-side-menu .phui-icon-view { + border-radius: 3px; +} + +.device-desktop .phui-profile-menu .phabricator-side-menu + .phui-list-item-href:hover { + background-color: {$menu.profile.background.hover}; + color: {$menu.profile.text.selected}; + transition: 0.2s; +} + +.phui-profile-menu .phabricator-side-menu + .phui-list-item-selected + .phui-list-item-icon, +.device-desktop .phui-profile-menu .phabricator-side-menu + .phui-list-item-href:hover + .phui-list-item-icon { + color: {$menu.profile.text.selected}; + transition: 0.2s; +} + +.phui-profile-menu .phabricator-side-menu .phui-list-item-selected + .phui-list-item-href { + background-color: {$menu.profile.background.selected}; + color: {$menu.profile.text.selected}; + transition: 0.2s; +} + +.phui-profile-menu .phabricator-side-menu .phui-divider { + margin: 4px 0; + border-bottom: 1px solid rgba(0, 0, 0, 0.2); +} + +.phui-profile-menu .phabricator-side-menu .phui-motivator { + white-space: normal; + padding: 18px 15px; + font-size: 12px; + color: {$menu.profile.text}; +} + +.phui-profile-menu .phabricator-side-menu .phui-motivator .phui-icon-view { + position: static; + font-size: 12px; + color: {$menu.profile.text}; +} + +.phui-profile-menu .phabricator-side-menu .phui-profile-menu-spacer { + box-sizing: border-box; + height: {$menu.profile.item.height}; +} + +.phui-profile-menu .phui-profile-menu-collapsed .phabricator-side-menu + .phui-profile-menu-footer + .phui-list-item-name { + display: none; +} + +.phui-profile-menu .phui-profile-menu-expanded + .phui-profile-menu-visible-when-collapsed, +.phui-profile-menu .phui-profile-menu-collapsed + .phui-profile-menu-visible-when-expanded { + display: none; +} + + +.phui-profile-menu .phui-profile-menu-collapsed .phabricator-side-menu + .phui-profile-menu-footer .phui-list-item-href { + padding: 20px 0 20px; +} + +.phui-profile-menu .phabricator-side-menu .phui-profile-menu-footer + .phui-list-item-href:hover { + background: transparent; +} + +.phui-profile-menu .phui-profile-menu-collapsed .phabricator-side-menu + .phui-profile-menu-footer .phui-list-item-href .phui-list-item-icon { + top: 8px; +} + +.phui-profile-menu .phui-profile-menu-footer .phui-icon-circle { + border-color: {$menu.profile.text}; +} + +.phui-profile-menu .phui-profile-menu-footer .phui-icon-circle .phui-icon-view { + color: {$menu.profile.text}; +} + +.phui-profile-menu .phui-profile-menu-footer .phui-list-item-href:hover + .phui-icon-circle, +.phui-profile-menu .phui-list-item-selected.phui-profile-menu-footer + .phui-icon-circle { + border-color: #fff; +} + +.phui-profile-menu .phui-profile-menu-footer .phui-list-item-href:hover + .phui-icon-circle .phui-icon-view, +.phui-profile-menu .phui-list-item-selected.phui-profile-menu-footer + .phui-icon-circle .phui-icon-view { + color: #fff; +} + +.phui-profile-menu .phui-profile-menu-footer + .phui-icon-circle.phui-list-item-icon { + font-size: 11px; +} + +div.phui-profile-menu .phabricator-side-menu .phui-profile-menu-footer-1 { + bottom: 40px; + position: fixed; + background-color: {$menu.profile.background}; +} + +div.phui-profile-menu .phabricator-side-menu .phui-profile-menu-footer-2 { + bottom: 0; + position: fixed; + background-color: {$menu.profile.background}; +} + +.phui-profile-menu .phui-profile-menu-footer-1, +.phui-profile-menu .phui-profile-menu-footer-2 { + width: {$menu.profile.width}; + transition: .2s; +} + +.phui-profile-menu .phui-profile-menu-collapsed .phui-profile-menu-footer-1, +.phui-profile-menu .phui-profile-menu-collapsed .phui-profile-menu-footer-2 { + width: {$menu.profile.width.collapsed}; + transition: .2s; +} + +.phui-profile-menu .phabricator-side-menu + .phui-list-item-selected.phui-profile-menu-footer .phui-list-item-href { + background: transparent; +} diff --git a/webroot/rsrc/css/phui/phui-workboard-view.css b/webroot/rsrc/css/phui/phui-workboard-view.css index e6817c6254..5d4ed5dd1c 100644 --- a/webroot/rsrc/css/phui/phui-workboard-view.css +++ b/webroot/rsrc/css/phui/phui-workboard-view.css @@ -38,7 +38,12 @@ } .device-desktop .project-board-wrapper .phui-workboard-view-shadow { - left: 53px; + left: 253px; +} + +.device-desktop .phui-profile-menu-collapsed .project-board-wrapper + .phui-workboard-view-shadow { + left: 101px; } .device-desktop .phui-workboard-view .aphront-multi-column-fixed @@ -86,13 +91,3 @@ margin: 8px 0 2px 0; padding: 0; } - -.device-desktop .phabricator-icon-nav.project-board-nav - .phabricator-nav-local { - margin-top: 64px; -} - -.device-desktop .phabricator-icon-nav.project-board-nav - .phabricator-nav-content { - margin: 0; -} diff --git a/webroot/rsrc/css/sprite-main-header.css b/webroot/rsrc/css/sprite-main-header.css deleted file mode 100644 index de2ab7a694..0000000000 --- a/webroot/rsrc/css/sprite-main-header.css +++ /dev/null @@ -1,60 +0,0 @@ -/** - * @provides sprite-main-header-css - * @generated - */ - -.sprite-main-header { - background-image: url(/rsrc/image/sprite-main-header.png); - background-repeat: repeat-x; -} - - - - -.phui-theme-applebloom .phabricator-main-menu-background { - background-position: 0px 0px; -} - -.phui-theme-blindigo .phabricator-main-menu-background { - background-position: 0px -45px; -} - -.phui-theme-blue .phabricator-main-menu-background { - background-position: 0px -90px; -} - -.phui-theme-dark .phabricator-main-menu-background { - background-position: 0px -135px; -} - -.phui-theme-fluttershy .phabricator-main-menu-background { - background-position: 0px -180px; -} - -.phui-theme-green .phabricator-main-menu-background { - background-position: 0px -225px; -} - -.phui-theme-indigo .phabricator-main-menu-background { - background-position: 0px -270px; -} - -.phui-theme-light .phabricator-main-menu-background { - background-position: 0px -315px; -} - -.phui-theme-nightmaremoon .phabricator-main-menu-background { - background-position: 0px -360px; -} - -.phui-theme-red .phabricator-main-menu-background { - background-position: 0px -405px; -} - -.phui-theme-scootaloo .phabricator-main-menu-background { - background-position: 0px -450px; -} - -.phui-theme-yellow .phabricator-main-menu-background { - background-position: 0px -495px; -} diff --git a/webroot/rsrc/css/sprite-projects.css b/webroot/rsrc/css/sprite-projects.css deleted file mode 100644 index 16abde0551..0000000000 --- a/webroot/rsrc/css/sprite-projects.css +++ /dev/null @@ -1,308 +0,0 @@ -/** - * @provides sprite-projects-css - * @generated - */ - -.sprite-projects { - background-image: url(/rsrc/image/sprite-projects.png); - background-repeat: no-repeat; -} - -@media -only screen and (min-device-pixel-ratio: 1.5), -only screen and (-webkit-min-device-pixel-ratio: 1.5), -only screen and (min-resolution: 1.5dppx) { - .sprite-projects { - background-image: url(/rsrc/image/sprite-projects-X2.png); - background-size: 408px 459px; - } -} - - -.projects-8ball { - background-position: 0px 0px; -} - -.projects-alien { - background-position: -51px 0px; -} - -.projects-announce { - background-position: -102px 0px; -} - -.projects-art { - background-position: -153px 0px; -} - -.projects-award { - background-position: -204px 0px; -} - -.projects-bacon { - background-position: -255px 0px; -} - -.projects-bandaid { - background-position: -306px 0px; -} - -.projects-beer { - background-position: -357px 0px; -} - -.projects-bomb { - background-position: 0px -51px; -} - -.projects-briefcase { - background-position: -51px -51px; -} - -.projects-bug { - background-position: -102px -51px; -} - -.projects-calendar { - background-position: -153px -51px; -} - -.projects-cloud { - background-position: -204px -51px; -} - -.projects-coffee { - background-position: -255px -51px; -} - -.projects-creditcard { - background-position: -306px -51px; -} - -.projects-death { - background-position: -357px -51px; -} - -.projects-desktop { - background-position: 0px -102px; -} - -.projects-dropbox { - background-position: -51px -102px; -} - -.projects-education { - background-position: -102px -102px; -} - -.projects-experimental { - background-position: -153px -102px; -} - -.projects-fa-briefcase { - background-position: -204px -102px; -} - -.projects-fa-bug { - background-position: -255px -102px; -} - -.projects-fa-building { - background-position: -306px -102px; -} - -.projects-fa-calendar { - background-position: -357px -102px; -} - -.projects-fa-cloud { - background-position: 0px -153px; -} - -.projects-fa-credit-card { - background-position: -51px -153px; -} - -.projects-fa-envelope { - background-position: -102px -153px; -} - -.projects-fa-flag-checkered { - background-position: -153px -153px; -} - -.projects-fa-flask { - background-position: -204px -153px; -} - -.projects-fa-folder { - background-position: -255px -153px; -} - -.projects-fa-lock { - background-position: -306px -153px; -} - -.projects-fa-tags { - background-position: -357px -153px; -} - -.projects-fa-trash-o { - background-position: 0px -204px; -} - -.projects-fa-truck { - background-position: -51px -204px; -} - -.projects-fa-umbrella { - background-position: -102px -204px; -} - -.projects-fa-users { - background-position: -153px -204px; -} - -.projects-facebook { - background-position: -204px -204px; -} - -.projects-facility { - background-position: -255px -204px; -} - -.projects-film { - background-position: -306px -204px; -} - -.projects-forked { - background-position: -357px -204px; -} - -.projects-games { - background-position: 0px -255px; -} - -.projects-ghost { - background-position: -51px -255px; -} - -.projects-gift { - background-position: -102px -255px; -} - -.projects-globe { - background-position: -153px -255px; -} - -.projects-golf { - background-position: -204px -255px; -} - -.projects-heart { - background-position: -255px -255px; -} - -.projects-intergalactic { - background-position: -306px -255px; -} - -.projects-lock { - background-position: -357px -255px; -} - -.projects-mail { - background-position: 0px -306px; -} - -.projects-martini { - background-position: -51px -306px; -} - -.projects-medical { - background-position: -102px -306px; -} - -.projects-mobile { - background-position: -153px -306px; -} - -.projects-music { - background-position: -204px -306px; -} - -.projects-news { - background-position: -255px -306px; -} - -.projects-orgchart { - background-position: -306px -306px; -} - -.projects-peoples { - background-position: -357px -306px; -} - -.projects-piechart { - background-position: 0px -357px; -} - -.projects-poison { - background-position: -51px -357px; -} - -.projects-putabirdonit { - background-position: -102px -357px; -} - -.projects-radiate { - background-position: -153px -357px; -} - -.projects-savings { - background-position: -204px -357px; -} - -.projects-search { - background-position: -255px -357px; -} - -.projects-shield { - background-position: -306px -357px; -} - -.projects-speed { - background-position: -357px -357px; -} - -.projects-sprint { - background-position: 0px -408px; -} - -.projects-star { - background-position: -51px -408px; -} - -.projects-storage { - background-position: -102px -408px; -} - -.projects-tablet { - background-position: -153px -408px; -} - -.projects-travel { - background-position: -204px -408px; -} - -.projects-twitter { - background-position: -255px -408px; -} - -.projects-warning { - background-position: -306px -408px; -} - -.projects-whale { - background-position: -357px -408px; -} diff --git a/webroot/rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadOnDemandSource.js b/webroot/rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadOnDemandSource.js index fd601478a0..5b301dc6fe 100644 --- a/webroot/rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadOnDemandSource.js +++ b/webroot/rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadOnDemandSource.js @@ -38,7 +38,7 @@ JX.install('TypeaheadOnDemandSource', { lastChange : null, haveData : null, - didChange : function(raw_value) { + didChange : function(raw_value, force) { this.lastChange = JX.now(); var value = this.normalize(raw_value); @@ -59,10 +59,19 @@ JX.install('TypeaheadOnDemandSource', { } this.waitForResults(); - setTimeout( - JX.bind(this, this.sendRequest, this.lastChange, value, raw_value), - this.getQueryDelay() - ); + + var send_request = JX.bind( + this, + this.sendRequest, + this.lastChange, + value, + raw_value); + + if (force) { + send_request(); + } else { + setTimeout(send_request, this.getQueryDelay()); + } } }, diff --git a/webroot/rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadSource.js b/webroot/rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadSource.js index e4c68f3742..74dc1c2453 100644 --- a/webroot/rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadSource.js +++ b/webroot/rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadSource.js @@ -289,7 +289,7 @@ JX.install('TypeaheadSource', { this.filterAndSortHits(value, hits); var nodes = this.renderNodes(value, hits); - this.invoke('resultsready', nodes, value); + this.invoke('resultsready', nodes, value, partial); if (!partial) { this.invoke('complete'); } diff --git a/webroot/rsrc/image/sprite-main-header.png b/webroot/rsrc/image/sprite-main-header.png deleted file mode 100644 index f0211bd79e..0000000000 Binary files a/webroot/rsrc/image/sprite-main-header.png and /dev/null differ diff --git a/webroot/rsrc/image/sprite-projects-X2.png b/webroot/rsrc/image/sprite-projects-X2.png deleted file mode 100644 index 3b3525417a..0000000000 Binary files a/webroot/rsrc/image/sprite-projects-X2.png and /dev/null differ diff --git a/webroot/rsrc/image/sprite-projects.png b/webroot/rsrc/image/sprite-projects.png deleted file mode 100644 index 8c85c59e1b..0000000000 Binary files a/webroot/rsrc/image/sprite-projects.png and /dev/null differ diff --git a/webroot/rsrc/js/application/files/behavior-icon-composer.js b/webroot/rsrc/js/application/files/behavior-icon-composer.js index 8f574c0dc4..3a158a5ed9 100644 --- a/webroot/rsrc/js/application/files/behavior-icon-composer.js +++ b/webroot/rsrc/js/application/files/behavior-icon-composer.js @@ -41,9 +41,9 @@ JX.behavior('icon-composer', function(config) { nodes.colorInput.value = selected.color; nodes.iconInput.value = selected.icon; - var classes = ['phui-icon-view', 'sprite-projects']; + var classes = ['phui-icon-view', 'phui-font-fa', 'compose-icon-bg']; classes.push('compose-background-' + selected.color); - classes.push('projects-' + selected.icon); + classes.push(selected.icon); nodes.preview.className = classes.join(' '); }; diff --git a/webroot/rsrc/js/application/herald/HeraldRuleEditor.js b/webroot/rsrc/js/application/herald/HeraldRuleEditor.js index 6514567e19..ba01c9bef3 100644 --- a/webroot/rsrc/js/application/herald/HeraldRuleEditor.js +++ b/webroot/rsrc/js/application/herald/HeraldRuleEditor.js @@ -293,7 +293,17 @@ JX.install('HeraldRuleEditor', { }, function(map) { for (var k in map) { - var v = JX.Prefab.transformDatasourceResults(map[k]); + var v = map[k]; + + // The control value may be set from wire values from the server, + // or a transformed value from another control, or a bare string + // value from another control. + if (typeof v == 'string') { + v = v; + } else if (!v.hasOwnProperty('id')) { + v = JX.Prefab.transformDatasourceResults(v); + } + build.tokenizer.addToken(k, v); } }]; diff --git a/webroot/rsrc/js/core/Prefab.js b/webroot/rsrc/js/core/Prefab.js index d48b295f0d..5948958c8f 100644 --- a/webroot/rsrc/js/core/Prefab.js +++ b/webroot/rsrc/js/core/Prefab.js @@ -99,81 +99,8 @@ JX.install('Prefab', { datasource = new JX.TypeaheadPreloadedSource(config.src); } - // Sort results so that the viewing user always comes up first; after - // that, prefer unixname matches to realname matches. - - var sort_handler = function(value, list, cmp) { - var priority_hits = {}; - var self_hits = {}; - - var tokens = this.tokenize(value); - - for (var ii = 0; ii < list.length; ii++) { - var item = list[ii]; - - for (var jj = 0; jj < tokens.length; jj++) { - if (item.name.indexOf(tokens[jj]) === 0) { - priority_hits[item.id] = true; - } - } - - if (!item.priority) { - continue; - } - - if (config.username && item.priority == config.username) { - self_hits[item.id] = true; - } - - for (var hh = 0; hh < tokens.length; hh++) { - if (item.priority.substr(0, tokens[hh].length) == tokens[hh]) { - priority_hits[item.id] = true; - } - } - } - - list.sort(function(u, v) { - if (self_hits[u.id] != self_hits[v.id]) { - return self_hits[v.id] ? 1 : -1; - } - - // If one result is open and one is closed, show the open result - // first. The "!" tricks here are becaused closed values are display - // strings, so the value is either `null` or some truthy string. If - // we compare the values directly, we'll apply this rule to two - // objects which are both closed but for different reasons, like - // "Archived" and "Disabled". - - var u_open = !u.closed; - var v_open = !v.closed; - - if (u_open != v_open) { - if (u_open) { - return -1; - } else { - return 1; - } - } - - if (priority_hits[u.id] != priority_hits[v.id]) { - return priority_hits[v.id] ? 1 : -1; - } - - // Sort users ahead of other result types. - if (u.priorityType != v.priorityType) { - if (u.priorityType == 'user') { - return -1; - } - if (v.priorityType == 'user') { - return 1; - } - } - - return cmp(u, v); - }); - }; - - datasource.setSortHandler(JX.bind(datasource, sort_handler)); + datasource.setSortHandler( + JX.bind(datasource, JX.Prefab.sortHandler, config)); datasource.setFilterHandler(JX.Prefab.filterClosedResults); datasource.setTransformer(JX.Prefab.transformDatasourceResults); @@ -251,6 +178,80 @@ JX.install('Prefab', { }; }, + sortHandler: function(config, value, list, cmp) { + // Sort results so that the viewing user always comes up first; after + // that, prefer unixname matches to realname matches. + var priority_hits = {}; + var self_hits = {}; + + var tokens = this.tokenize(value); + + for (var ii = 0; ii < list.length; ii++) { + var item = list[ii]; + + for (var jj = 0; jj < tokens.length; jj++) { + if (item.name.indexOf(tokens[jj]) === 0) { + priority_hits[item.id] = true; + } + } + + if (!item.priority) { + continue; + } + + if (config.username && item.priority == config.username) { + self_hits[item.id] = true; + } + + for (var hh = 0; hh < tokens.length; hh++) { + if (item.priority.substr(0, tokens[hh].length) == tokens[hh]) { + priority_hits[item.id] = true; + } + } + } + + list.sort(function(u, v) { + if (self_hits[u.id] != self_hits[v.id]) { + return self_hits[v.id] ? 1 : -1; + } + + // If one result is open and one is closed, show the open result + // first. The "!" tricks here are becaused closed values are display + // strings, so the value is either `null` or some truthy string. If + // we compare the values directly, we'll apply this rule to two + // objects which are both closed but for different reasons, like + // "Archived" and "Disabled". + + var u_open = !u.closed; + var v_open = !v.closed; + + if (u_open != v_open) { + if (u_open) { + return -1; + } else { + return 1; + } + } + + if (priority_hits[u.id] != priority_hits[v.id]) { + return priority_hits[v.id] ? 1 : -1; + } + + // Sort users ahead of other result types. + if (u.priorityType != v.priorityType) { + if (u.priorityType == 'user') { + return -1; + } + if (v.priorityType == 'user') { + return 1; + } + } + + return cmp(u, v); + }); + }, + + /** * Filter callback for tokenizers and typeaheads which filters out closed * or disabled objects unless they are the only options. @@ -325,7 +326,8 @@ JX.install('Prefab', { sprite: fields[10], color: fields[11], tokenType: fields[12], - unique: fields[13] || false + unique: fields[13] || false, + autocomplete: fields[14] }; }, diff --git a/webroot/rsrc/js/core/behavior-phabricator-remarkup-assist.js b/webroot/rsrc/js/core/behavior-phabricator-remarkup-assist.js index 9dabffeb10..f09070e42e 100644 --- a/webroot/rsrc/js/core/behavior-phabricator-remarkup-assist.js +++ b/webroot/rsrc/js/core/behavior-phabricator-remarkup-assist.js @@ -7,6 +7,7 @@ * phabricator-textareautils * javelin-workflow * javelin-vector + * phuix-autocomplete */ JX.behavior('phabricator-remarkup-assist', function(config) { @@ -293,4 +294,13 @@ JX.behavior('phabricator-remarkup-assist', function(config) { assist(area, data.action, root, e.getNode('remarkup-assist')); }); + var autocomplete = new JX.PHUIXAutocomplete() + .setArea(area); + + for (var k in config.autocompleteMap) { + autocomplete.addAutocomplete(k, config.autocompleteMap[k]); + } + + autocomplete.start(); + }); diff --git a/webroot/rsrc/js/phui/behavior-phui-profile-menu.js b/webroot/rsrc/js/phui/behavior-phui-profile-menu.js new file mode 100644 index 0000000000..28d01ec122 --- /dev/null +++ b/webroot/rsrc/js/phui/behavior-phui-profile-menu.js @@ -0,0 +1,39 @@ +/** + * @provides javelin-behavior-phui-profile-menu + * @requires javelin-behavior + * javelin-stratcom + * javelin-dom + */ + +JX.behavior('phui-profile-menu', function(config) { + // NOTE: This behavior is not initialized in the rendering pipeline for the + // menu, so it can get initialized when we build but do not render a menu + // (for example, when a page like the panel edit page only has items in + // the mobile/application menu, and does not show the profile menu). For now, + // just bail if we can't find the menu. + + try { + var menu_node = JX.$(config.menuID); + } catch (ex) { + return; + } + + var collapse_node = JX.$(config.collapseID); + + var is_collapsed = config.isCollapsed; + + JX.DOM.listen(collapse_node, 'click', null, function(e) { + is_collapsed = !is_collapsed; + JX.DOM.alterClass(menu_node, 'phui-profile-menu-collapsed', is_collapsed); + JX.DOM.alterClass(menu_node, 'phui-profile-menu-expanded', !is_collapsed); + + if (config.settingsURI) { + new JX.Request(config.settingsURI) + .setData({value: (is_collapsed ? 1 : 0)}) + .send(); + } + + e.kill(); + }); + +}); diff --git a/webroot/rsrc/js/phuix/PHUIXAutocomplete.js b/webroot/rsrc/js/phuix/PHUIXAutocomplete.js new file mode 100644 index 0000000000..3bc5cf0166 --- /dev/null +++ b/webroot/rsrc/js/phuix/PHUIXAutocomplete.js @@ -0,0 +1,712 @@ +/** + * @provides phuix-autocomplete + * @requires javelin-install + * javelin-dom + * phuix-icon-view + * phabricator-prefab + */ + +JX.install('PHUIXAutocomplete', { + + construct: function() { + this._map = {}; + this._datasources = {}; + this._listNodes = []; + this._resultMap = {}; + }, + + members: { + _area: null, + _active: false, + _cursorHead: null, + _cursorTail: null, + _pixelHead: null, + _pixelTail: null, + _map: null, + _datasource: null, + _datasources: null, + _value: null, + _node: null, + _echoNode: null, + _listNode: null, + _promptNode: null, + _focus: null, + _focusRef: null, + _listNodes: null, + _x: null, + _y: null, + _visible: false, + _resultMap: null, + + setArea: function(area) { + this._area = area; + return this; + }, + + addAutocomplete: function(code, spec) { + this._map[code] = spec; + return this; + }, + + start: function() { + var area = this._area; + + JX.DOM.listen(area, 'keypress', null, JX.bind(this, this._onkeypress)); + + JX.DOM.listen( + area, + ['click', 'keyup', 'keydown', 'keypress'], + null, + JX.bind(this, this._update)); + + var select = JX.bind(this, this._onselect); + JX.DOM.listen(this._getNode(), 'mousedown', 'typeahead-result', select); + + var device = JX.bind(this, this._ondevice); + JX.Stratcom.listen('phabricator-device-change', null, device); + + // When the user clicks away from the textarea, deactivate. + var deactivate = JX.bind(this, this._deactivate); + JX.DOM.listen(area, 'blur', null, deactivate); + }, + + _getSpec: function() { + return this._map[this._active]; + }, + + _ondevice: function() { + if (JX.Device.getDevice() != 'desktop') { + this._deactivate(); + } + }, + + _activate: function(code) { + if (JX.Device.getDevice() != 'desktop') { + return; + } + + if (!this._map[code]) { + return; + } + + var area = this._area; + var range = JX.TextAreaUtils.getSelectionRange(area); + + // Check the character immediately before the trigger character. We'll + // only activate the typeahead if it's something that we think a user + // might reasonably want to autocomplete after, like a space, newline, + // or open parenthesis. For example, if a user types "alincoln@", + // the prior letter will be the last "n" in "alincoln". They are probably + // typing an email address, not a username, so we don't activate the + // autocomplete. + var head = range.start; + var prior; + if (head > 1) { + prior = area.value.substring(head - 2, head - 1); + } else { + prior = ''; + } + + switch (prior) { + case '': + case ' ': + case '\n': + case '\t': + case '(': // Might be "(@username, what do you think?)". + case '-': // Might be an unnumbered list. + case '.': // Might be a numbered list. + case '|': // Might be a table cell. + case '>': // Might be a blockquote. + case '!': // Might be a blockquote attribution line. + case ':': // Might be a "NOTE:". + // We'll let these autocomplete. + break; + default: + // We bail out on anything else, since the user is probably not + // typing a username or project tag. + return; + } + + // Get all the text on the current line. If the line only contains + // whitespace, don't actiavte: the user is probably typing code or a + // numbered list. + var line = area.value.substring(0, head - 1); + line = line.split('\n'); + line = line[line.length - 1]; + if (line.match(/^\s+$/)) { + return; + } + + this._cursorHead = head; + this._cursorTail = range.end; + this._pixelHead = JX.TextAreaUtils.getPixelDimensions( + area, + range.start, + range.end); + + var spec = this._map[code]; + if (!this._datasources[code]) { + var datasource = new JX.TypeaheadOnDemandSource(spec.datasourceURI); + datasource.listen( + 'resultsready', + JX.bind(this, this._onresults, code)); + + datasource.setTransformer(JX.bind(this, this._transformresult)); + datasource.setSortHandler( + JX.bind(datasource, JX.Prefab.sortHandler, {})); + datasource.setFilterHandler(JX.Prefab.filterClosedResults); + + this._datasources[code] = datasource; + } + + this._datasource = this._datasources[code]; + this._active = code; + + var head_icon = new JX.PHUIXIconView() + .setIcon(spec.headerIcon) + .getNode(); + var head_text = spec.headerText; + + var node = this._getPromptNode(); + JX.DOM.setContent(node, [head_icon, head_text]); + }, + + _transformresult: function(fields) { + var map = JX.Prefab.transformDatasourceResults(fields); + + var icon; + if (map.icon) { + icon = new JX.PHUIXIconView() + .setIcon(map.icon) + .getNode(); + } + + map.display = [icon, map.displayName]; + + return map; + }, + + _deactivate: function() { + var node = this._getNode(); + JX.DOM.hide(node); + + this._active = false; + this._visible = false; + }, + + _onkeypress: function(e) { + var r = e.getRawEvent(); + + if (r.metaKey || r.altKey || r.ctrlKey) { + return; + } + + var code = r.charCode; + if (this._map[code]) { + setTimeout(JX.bind(this, this._activate, code), 0); + } + }, + + _onresults: function(code, nodes, value, partial) { + // Even if these results are out of date, we still want to fill in the + // result map so we can terminate things later. + if (!partial) { + if (!this._resultMap[code]) { + this._resultMap[code] = {}; + } + + var hits = []; + for (var ii = 0; ii < nodes.length; ii++) { + var result = this._datasources[code].getResult(nodes[ii].rel); + if (!result) { + hits = null; + break; + } + + if (!result.autocomplete || !result.autocomplete.length) { + hits = null; + break; + } + + hits.push(result.autocomplete); + } + + if (hits !== null) { + this._resultMap[code][value] = hits; + } + } + + if (code !== this._active) { + return; + } + + if (value !== this._value) { + return; + } + + if (this._isTerminatedString(value)) { + if (this._hasUnrefinableResults(value)) { + this._deactivate(); + return; + } + } + + var list = this._getListNode(); + JX.DOM.setContent(list, nodes); + + this._listNodes = nodes; + + var old_ref = this._focusRef; + this._clearFocus(); + + for (var ii = 0; ii < nodes.length; ii++) { + if (nodes[ii].rel == old_ref) { + this._setFocus(ii); + break; + } + } + + if (this._focus === null && nodes.length) { + this._setFocus(0); + } + + this._redraw(); + }, + + _setFocus: function(idx) { + if (!this._listNodes[idx]) { + this._clearFocus(); + return false; + } + + if (this._focus !== null) { + JX.DOM.alterClass(this._listNodes[this._focus], 'focused', false); + } + + this._focus = idx; + this._focusRef = this._listNodes[idx].rel; + JX.DOM.alterClass(this._listNodes[idx], 'focused', true); + + return true; + }, + + _changeFocus: function(delta) { + if (this._focus === null) { + return false; + } + + return this._setFocus(this._focus + delta); + }, + + _clearFocus: function() { + this._focus = null; + this._focusRef = null; + }, + + _onselect: function (e) { + if (!e.isNormalMouseEvent()) { + // Eat right clicks, control clicks, etc., on the results. These can + // not do anything meaningful and if we let them through they'll blur + // the field and dismiss the results. + e.kill(); + return; + } + + var target = e.getNode('typeahead-result'); + + for (var ii = 0; ii < this._listNodes.length; ii++) { + if (this._listNodes[ii] === target) { + this._setFocus(ii); + this._autocomplete(); + break; + } + } + + this._deactivate(); + e.kill(); + }, + + _getSuffixes: function() { + return [' ', ':', ',', ')']; + }, + + _getCancelCharacters: function() { + // The "." character does not cancel because of projects named + // "node.js" or "blog.mycompany.com". + return ['#', '@', ',', '!', '?']; + }, + + _getTerminators: function() { + return [' ', ':', ',', '.', '!', '?']; + }, + + _isTerminatedString: function(string) { + var terminators = this._getTerminators(); + for (var ii = 0; ii < terminators.length; ii++) { + var term = terminators[ii]; + if (string.substring(string.length - term.length) == term) { + return true; + } + } + + return false; + }, + + _hasUnrefinableResults: function(query) { + if (!this._resultMap[this._active]) { + return false; + } + + var map = this._resultMap[this._active]; + + for (var ii = 1; ii < query.length; ii++) { + var prefix = query.substring(0, ii); + if (map.hasOwnProperty(prefix)) { + var results = map[prefix]; + + // If any prefix of the query has no results, the full query also + // has no results so we can not refine them. + if (!results.length) { + return true; + } + + // If there is exactly one match and the it is a prefix of the query, + // we can safely assume the user just typed out the right result + // from memory and doesn't need to refine it. + if (results.length == 1) { + // Strip the first character off, like a "#" or "@". + var result = results[0].substring(1); + + if (query.length >= result.length) { + if (query.substring(0, result.length) === result) { + return true; + } + } + } + } + } + + return false; + }, + + _trim: function(str) { + var suffixes = this._getSuffixes(); + for (var ii = 0; ii < suffixes.length; ii++) { + if (str.substring(str.length - suffixes[ii].length) == suffixes[ii]) { + str = str.substring(0, str.length - suffixes[ii].length); + } + } + return str; + }, + + _update: function(e) { + if (!this._active) { + return; + } + + var special = e.getSpecialKey(); + + // Deactivate if the user types escape. + if (special == 'esc') { + this._deactivate(); + e.kill(); + return; + } + + var area = this._area; + + if (e.getType() == 'keydown') { + if (special == 'up' || special == 'down') { + var delta = (special == 'up') ? -1 : +1; + if (!this._changeFocus(delta)) { + this._deactivate(); + } + e.kill(); + return; + } + } + + if (special == 'tab' || special == 'return') { + var r = e.getRawEvent(); + if (r.shiftKey && special == 'tab') { + // Don't treat "Shift + Tab" as an autocomplete action. Instead, + // let it through normally so the focus shifts to the previous + // control. + this._deactivate(); + return; + } + + // If we autocomplete, we're done. Otherwise, just eat the event. This + // happens if you type too fast and try to tab complete before results + // load. + if (this._autocomplete()) { + this._deactivate(); + } + + e.kill(); + return; + } + + // Deactivate if the user moves the cursor to the left of the assist + // range. For example, they might press the "left" arrow to move the + // cursor to the left, or click in the textarea prior to the active + // range. + var range = JX.TextAreaUtils.getSelectionRange(area); + if (range.start < this._cursorHead) { + this._deactivate(); + return; + } + + // Deactivate if the user moves the cursor to the right of the assist + // range. For example, they might click later in the document. If the user + // is pressing the "right" arrow key, they are not allowed to move the + // cursor beyond the existing end of the text range. If they are pressing + // other keys, assume they're typing and allow the tail to move forward + // one character. + var margin; + if (special == 'right') { + margin = 0; + } else { + margin = 1; + } + + var tail = this._cursorTail; + + if ((range.start > tail + margin) || (range.end > tail + margin)) { + this._deactivate(); + return; + } + + this._cursorTail = Math.max(this._cursorTail, range.end); + + var text = area.value.substring( + this._cursorHead, + this._cursorTail); + + this._value = text; + + var pixels = JX.TextAreaUtils.getPixelDimensions( + area, + range.start, + range.end); + + var x = this._pixelHead.start.x; + var y = Math.max(this._pixelHead.end.y, pixels.end.y) + 24; + + // If the first character after the trigger is a space, just deactivate + // immediately. This occurs if a user types a numbered list using "#". + if (text.length && text[0] == ' ') { + this._deactivate(); + return; + } + + var trim = this._trim(text); + + // Deactivate immediately if a user types a character that we are + // reasonably sure means they don't want to use the autocomplete. For + // example, "##" is almost certainly a header or monospaced text, not + // a project autocompletion. + var cancels = this._getCancelCharacters(); + for (var ii = 0; ii < cancels.length; ii++) { + if (trim.indexOf(cancels[ii]) !== -1) { + this._deactivate(); + return; + } + } + + // If the input is terminated by a space or another word-terminating + // punctuation mark, we're going to deactivate if the results can not + // be refined by addding more words. + + // The idea is that if you type "@alan ab", you're allowed to keep + // editing "ab" until you type a space, period, or other terminator, + // since you might not be sure how to spell someone's last name or the + // second word of a project. + + // Once you do terminate a word, if the words you have have entered match + // nothing or match only one exact match, we can safely deactivate and + // assume you're just typing text because further words could never + // refine the result set. + + var force; + if (this._isTerminatedString(text)) { + if (this._hasUnrefinableResults(text)) { + this._deactivate(); + return; + } + force = true; + } else { + force = false; + } + + this._datasource.didChange(trim, force); + + this._x = x; + this._y = y; + + var hint = trim; + if (hint.length) { + // We only show the autocompleter after the user types at least one + // character. For example, "@" does not trigger it, but "@d" does. + this._visible = true; + } else { + hint = this._getSpec().hintText; + } + + var echo = this._getEchoNode(); + JX.DOM.setContent(echo, hint); + + this._redraw(); + }, + + _redraw: function() { + if (!this._visible) { + return; + } + + var node = this._getNode(); + JX.DOM.show(node); + + var p = new JX.Vector(this._x, this._y); + var s = JX.Vector.getScroll(); + var v = JX.Vector.getViewport(); + + // If the menu would run off the bottom of the screen when showing the + // maximum number of possible choices, put it above instead. We're doing + // this based on the maximum size so the menu doesn't jump up and down + // as results arrive. + + var option_height = 30; + var extra_margin = 24; + if ((s.y + v.y) < (p.y + (5 * option_height) + extra_margin)) { + var d = JX.Vector.getDim(node); + p.y = p.y - d.y - 36; + } + + p.setPos(node); + }, + + _autocomplete: function() { + if (this._focus === null) { + return false; + } + + var area = this._area; + var head = this._cursorHead; + var tail = this._cursorTail; + + var text = area.value; + + var ref = this._focusRef; + var result = this._datasource.getResult(ref); + if (!result) { + return false; + } + + ref = result.autocomplete; + if (!ref || !ref.length) { + return false; + } + + // If the user types a string like "@username:" (with a trailing colon), + // then presses tab or return to pick the completion, don't destroy the + // trailing character. + var suffixes = this._getSuffixes(); + var value = this._value; + var found_suffix = false; + for (var ii = 0; ii < suffixes.length; ii++) { + var last = value.substring(value.length - suffixes[ii].length); + if (last == suffixes[ii]) { + ref += suffixes[ii]; + found_suffix = true; + break; + } + } + + // If we didn't find an existing suffix, add a space. + if (!found_suffix) { + ref = ref + ' '; + } + + area.value = text.substring(0, head - 1) + ref + text.substring(tail); + + var end = head + ref.length; + JX.TextAreaUtils.setSelectionRange(area, end, end); + + return true; + }, + + _getNode: function() { + if (!this._node) { + var head = this._getHeadNode(); + var list = this._getListNode(); + + this._node = JX.$N( + 'div', + { + className: 'phuix-autocomplete', + style: { + display: 'none' + } + }, + [head, list]); + + JX.DOM.hide(this._node); + + document.body.appendChild(this._node); + } + return this._node; + }, + + _getHeadNode: function() { + if (!this._headNode) { + this._headNode = JX.$N( + 'div', + { + className: 'phuix-autocomplete-head' + }, + [ + this._getPromptNode(), + this._getEchoNode() + ]); + } + + return this._headNode; + }, + + _getPromptNode: function() { + if (!this._promptNode) { + this._promptNode = JX.$N( + 'span', + { + className: 'phuix-autocomplete-prompt', + }); + } + return this._promptNode; + }, + + _getEchoNode: function() { + if (!this._echoNode) { + this._echoNode = JX.$N( + 'span', + { + className: 'phuix-autocomplete-echo' + }); + } + return this._echoNode; + }, + + _getListNode: function() { + if (!this._listNode) { + this._listNode = JX.$N( + 'div', + { + className: 'phuix-autocomplete-list' + }); + } + return this._listNode; + } + + } + +});