(stable) Promote 2017 Week 25
21
externals/octicons/LICENSE
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2012-2016 GitHub, Inc.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
194
externals/octicons/README.md
vendored
Normal file
|
@ -0,0 +1,194 @@
|
||||||
|
# GitHub Octicons
|
||||||
|
|
||||||
|
[![NPM version](https://img.shields.io/npm/v/octicons.svg)](https://www.npmjs.org/package/octicons)
|
||||||
|
[![Build Status](https://travis-ci.org/primer/octicons.svg?branch=master)](https://travis-ci.org/primer/octicons)
|
||||||
|
|
||||||
|
> Octicons are a scalable set of icons handcrafted with <3 by GitHub.
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
**NOTE:** The compiled files are located in `/build/`. This directory is located in the published npm package. Which means you can access it when you `npm install octicons`. You can also build this directory by following the [building octicons directions](#building-octicons). The files in the `/lib/` directory are the raw source files and are not compiled or optimized.
|
||||||
|
|
||||||
|
#### NPM
|
||||||
|
|
||||||
|
This repository is distributed with [npm][npm]. After [installing npm][install-npm], you can install `octicons` with this command.
|
||||||
|
|
||||||
|
```
|
||||||
|
$ npm install --save octicons
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
For all the usages, we recommend using the CSS located in `./build/octicons.css`. This is some simple CSS to normalize the icons and inherit colors.
|
||||||
|
|
||||||
|
### Spritesheet
|
||||||
|
|
||||||
|
With a [SVG sprite icon system](https://css-tricks.com/svg-sprites-use-better-icon-fonts/) you can include the sprite sheet located `./build/sprite.octicons.svg` after you [build the icons](#building-octicons) or from the npm package. There is a demo of how to use the spritesheet in the build directory also.
|
||||||
|
|
||||||
|
### Node
|
||||||
|
|
||||||
|
After installing `npm install octicons` you can access the icons like this.
|
||||||
|
|
||||||
|
```js
|
||||||
|
var octicons = require("octicons")
|
||||||
|
octicons.alert
|
||||||
|
// { keywords: [ 'warning', 'triangle', 'exclamation', 'point' ],
|
||||||
|
// path: '<path d="M8.865 1.52c-.18-.31-.51-.5-.87-.5s-.69.19-.87.5L.275 13.5c-.18.31-.18.69 0 1 .19.31.52.5.87.5h13.7c.36 0 .69-.19.86-.5.17-.31.18-.69.01-1L8.865 1.52zM8.995 13h-2v-2h2v2zm0-3h-2V6h2v4z"/>',
|
||||||
|
// height: '16',
|
||||||
|
// width: '16',
|
||||||
|
// symbol: 'alert',
|
||||||
|
// options:
|
||||||
|
// { version: '1.1',
|
||||||
|
// width: '16',
|
||||||
|
// height: '16',
|
||||||
|
// viewBox: '0 0 16 16',
|
||||||
|
// class: 'octicon octicon-alert',
|
||||||
|
// 'aria-hidden': 'true' },
|
||||||
|
// toSVG: [Function] }
|
||||||
|
```
|
||||||
|
|
||||||
|
There will be a key for every icon, with `keywords` and `svg`.
|
||||||
|
|
||||||
|
#### `octicons.alert.symbol`
|
||||||
|
|
||||||
|
Returns the string of the symbol name
|
||||||
|
|
||||||
|
```js
|
||||||
|
octicons.x.symbol
|
||||||
|
// "x"
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `octicons.person.path`
|
||||||
|
|
||||||
|
Path returns the string representation of the path of the icon.
|
||||||
|
|
||||||
|
```js
|
||||||
|
octicons.x.path
|
||||||
|
// <path d="M7.48 8l3.75 3.75-1.48 1.48L6 9.48l-3.75 3.75-1.48-1.48L4.52 8 .77 4.25l1.48-1.48L6 6.52l3.75-3.75 1.48 1.48z"></path>
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `octicons.issue.options`
|
||||||
|
|
||||||
|
This is a json object of all the `options` that will be added to the output tag.
|
||||||
|
|
||||||
|
```js
|
||||||
|
octicons.x.options
|
||||||
|
// { version: '1.1', width: '12', height: '16', viewBox: '0 0 12 16', class: 'octicon octicon-x', 'aria-hidden': 'true' }
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `octicons.alert.width`
|
||||||
|
|
||||||
|
Width is the icon's true width. Based on the svg view box width. _Note, this doesn't change if you scale it up with size options, it only is the natural width of the icon_
|
||||||
|
|
||||||
|
#### `octicons.alert.height`
|
||||||
|
|
||||||
|
Height is the icon's true height. Based on the svg view box height. _Note, this doesn't change if you scale it up with size options, it only is the natural height of the icon_
|
||||||
|
|
||||||
|
#### `keywords`
|
||||||
|
|
||||||
|
Returns an array of keywords for the icon. The data [comes from the octicons repository](https://github.com/primer/octicons/blob/master/lib/data.json). Consider contributing more aliases for the icons.
|
||||||
|
|
||||||
|
```js
|
||||||
|
octicons.x.keywords
|
||||||
|
// ["remove", "close", "delete"]
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `octicons.alert.toSVG()`
|
||||||
|
|
||||||
|
Returns a string of the svg tag
|
||||||
|
|
||||||
|
```js
|
||||||
|
octicons.x.toSVG()
|
||||||
|
// <svg version="1.1" width="12" height="16" viewBox="0 0 12 16" class="octicon octicon-x" aria-hidden="true"><path d="M7.48 8l3.75 3.75-1.48 1.48L6 9.48l-3.75 3.75-1.48-1.48L4.52 8 .77 4.25l1.48-1.48L6 6.52l3.75-3.75 1.48 1.48z"/></svg>
|
||||||
|
```
|
||||||
|
|
||||||
|
The `.toSVG()` method accepts an optional `options` object. This is used to add CSS classnames, a11y options, and sizing.
|
||||||
|
|
||||||
|
##### class
|
||||||
|
|
||||||
|
Add more CSS classes to the `<svg>` tag.
|
||||||
|
|
||||||
|
```js
|
||||||
|
octicons.x.toSVG({ "class": "close" })
|
||||||
|
// <svg version="1.1" width="12" height="16" viewBox="0 0 12 16" class="octicon octicon-x close" aria-hidden="true"><path d="M7.48 8l3.75 3.75-1.48 1.48L6 9.48l-3.75 3.75-1.48-1.48L4.52 8 .77 4.25l1.48-1.48L6 6.52l3.75-3.75 1.48 1.48z"/></svg>
|
||||||
|
```
|
||||||
|
|
||||||
|
##### aria-label
|
||||||
|
|
||||||
|
Add accessibility `aria-label` to the icon.
|
||||||
|
|
||||||
|
```js
|
||||||
|
octicons.x.toSVG({ "aria-label": "Close the window" })
|
||||||
|
// <svg version="1.1" width="12" height="16" viewBox="0 0 12 16" class="octicon octicon-x" aria-label="Close the window" role="img"><path d="M7.48 8l3.75 3.75-1.48 1.48L6 9.48l-3.75 3.75-1.48-1.48L4.52 8 .77 4.25l1.48-1.48L6 6.52l3.75-3.75 1.48 1.48z"/></svg>
|
||||||
|
```
|
||||||
|
|
||||||
|
##### width & height
|
||||||
|
|
||||||
|
Size the SVG icon larger using `width` & `height` independently or together.
|
||||||
|
|
||||||
|
```js
|
||||||
|
octicons.x.toSVG({ "width": 45 })
|
||||||
|
// <svg version="1.1" width="45" height="60" viewBox="0 0 12 16" class="octicon octicon-x" aria-hidden="true"><path d="M7.48 8l3.75 3.75-1.48 1.48L6 9.48l-3.75 3.75-1.48-1.48L4.52 8 .77 4.25l1.48-1.48L6 6.52l3.75-3.75 1.48 1.48z"/></svg>
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `octicons.alert.toSVGUse()`
|
||||||
|
|
||||||
|
Returns a string of the svg tag with the `<use>` tag, for use with the spritesheet located in the /build/ directory.
|
||||||
|
|
||||||
|
```js
|
||||||
|
octicons.x.toSVGUse()
|
||||||
|
// <svg version="1.1" width="12" height="16" viewBox="0 0 12 16" class="octicon octicon-x" aria-hidden="true"><use xlink:href="#x" /></svg>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Ruby
|
||||||
|
|
||||||
|
If your environment is Ruby on Rails, we have a [octicons_helper](https://github.com/primer/octicons_helper) gem available that renders SVG in your page. The octicons_helper uses the [octicons_gem](https://github.com/primer/octicons_gem) to do the computing and reading of the SVG files.
|
||||||
|
|
||||||
|
### Jekyll
|
||||||
|
|
||||||
|
For jekyll, there's a [jekyll-octicons](https://github.com/primer/jekyll-octicons) plugin available. This works exactly like the octicons_helper.
|
||||||
|
|
||||||
|
## Changing, adding, or deleting icons
|
||||||
|
|
||||||
|
1. Open the [Sketch document][sketch-document] in `/lib/`. Each icon exists as an artboard within our master Sketch document. If you’re adding an icon, duplicate one of the artboards and add your shapes to it. Be sure to give your artboard a name that makes sense.
|
||||||
|
2. Once you’re happy with your icon set, choose File > Export…
|
||||||
|
3. Choose all the artboards you’d like to export and then press “Export”
|
||||||
|
4. Export to `/lib/svg/`
|
||||||
|
|
||||||
|
You’ll next need to build your Octicons.
|
||||||
|
|
||||||
|
## Building Octicons
|
||||||
|
|
||||||
|
All the files you need will be in the `/build/` directory already, but if you’ve made changes to the `/lib/` directory and need to regenerate, follow these steps:
|
||||||
|
|
||||||
|
1. Open the Octicons directory in Terminal
|
||||||
|
2. `npm install` to install all dependencies for the project.
|
||||||
|
3. Run the command `npm run build`. This will run the grunt task to build the SVGs, placing them in the `/build/` directory.
|
||||||
|
|
||||||
|
## Publishing
|
||||||
|
|
||||||
|
If you have access to publish this repository, these are the steps to publishing. If you need access, contact [#design-systems](https://github.slack.com/archives/design-systems).
|
||||||
|
|
||||||
|
1. Update the [CHANGELOG.md](./CHANGELOG.md) with relevant version number and any updates made to the repository.
|
||||||
|
2. `npm version <newversion>` Run [npm version](https://docs.npmjs.com/cli/version) inputing the relevant version type. The versioning is [semver](http://semver.org/), so version appropriately based on what has changed.
|
||||||
|
3. `npm publish` This will publish the new version to npmjs.org
|
||||||
|
4. `git push && git push --tags` Push all these changes to origin.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
(c) 2012-2016 GitHub, Inc.
|
||||||
|
|
||||||
|
When using the GitHub logos, be sure to follow the [GitHub logo guidelines](https://github.com/logos).
|
||||||
|
|
||||||
|
_SVG License:_ [SIL OFL 1.1](http://scripts.sil.org/OFL)
|
||||||
|
Applies to all SVG files
|
||||||
|
|
||||||
|
_Code License:_ [MIT](./LICENSE)
|
||||||
|
Applies to all other files
|
||||||
|
|
||||||
|
[primer]: https://github.com/primer/primer
|
||||||
|
[docs]: http://primercss.io/
|
||||||
|
[npm]: https://www.npmjs.com/
|
||||||
|
[install-npm]: https://docs.npmjs.com/getting-started/installing-node
|
||||||
|
[sass]: http://sass-lang.com/
|
||||||
|
[sketch-document]: https://github.com/primer/octicons/blob/master/lib/octicons-master.sketch
|
BIN
resources/builtin/repo/building.png
Normal file
After Width: | Height: | Size: 4.1 KiB |
BIN
resources/builtin/repo/cloud.png
Normal file
After Width: | Height: | Size: 7.2 KiB |
BIN
resources/builtin/repo/code.png
Normal file
After Width: | Height: | Size: 3.9 KiB |
BIN
resources/builtin/repo/commit.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
resources/builtin/repo/database.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
resources/builtin/repo/desktop.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
resources/builtin/repo/gears.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
resources/builtin/repo/globe.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
resources/builtin/repo/locked.png
Normal file
After Width: | Height: | Size: 8.7 KiB |
BIN
resources/builtin/repo/microchip.png
Normal file
After Width: | Height: | Size: 5.8 KiB |
BIN
resources/builtin/repo/mobile.png
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
resources/builtin/repo/repo.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
resources/builtin/repo/servers.png
Normal file
After Width: | Height: | Size: 6.3 KiB |
|
@ -0,0 +1,2 @@
|
||||||
|
ALTER TABLE {$NAMESPACE}_repository.repository
|
||||||
|
ADD profileImagePHID VARBINARY(64);
|
4
resources/sql/autopatches/20170614.taskstatus.sql
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
/* Extend from 12 characters to 64. */
|
||||||
|
|
||||||
|
ALTER TABLE {$NAMESPACE}_maniphest.maniphest_task
|
||||||
|
CHANGE status status VARCHAR(64) COLLATE {$COLLATE_TEXT} NOT NULL;
|
|
@ -453,13 +453,10 @@ phutil_register_library_map(array(
|
||||||
'DifferentialGetRevisionCommentsConduitAPIMethod' => 'applications/differential/conduit/DifferentialGetRevisionCommentsConduitAPIMethod.php',
|
'DifferentialGetRevisionCommentsConduitAPIMethod' => 'applications/differential/conduit/DifferentialGetRevisionCommentsConduitAPIMethod.php',
|
||||||
'DifferentialGetRevisionConduitAPIMethod' => 'applications/differential/conduit/DifferentialGetRevisionConduitAPIMethod.php',
|
'DifferentialGetRevisionConduitAPIMethod' => 'applications/differential/conduit/DifferentialGetRevisionConduitAPIMethod.php',
|
||||||
'DifferentialGetWorkingCopy' => 'applications/differential/DifferentialGetWorkingCopy.php',
|
'DifferentialGetWorkingCopy' => 'applications/differential/DifferentialGetWorkingCopy.php',
|
||||||
'DifferentialGitHubLandingStrategy' => 'applications/differential/landing/DifferentialGitHubLandingStrategy.php',
|
|
||||||
'DifferentialGitSVNIDCommitMessageField' => 'applications/differential/field/DifferentialGitSVNIDCommitMessageField.php',
|
'DifferentialGitSVNIDCommitMessageField' => 'applications/differential/field/DifferentialGitSVNIDCommitMessageField.php',
|
||||||
'DifferentialHarbormasterField' => 'applications/differential/customfield/DifferentialHarbormasterField.php',
|
'DifferentialHarbormasterField' => 'applications/differential/customfield/DifferentialHarbormasterField.php',
|
||||||
'DifferentialHiddenComment' => 'applications/differential/storage/DifferentialHiddenComment.php',
|
'DifferentialHiddenComment' => 'applications/differential/storage/DifferentialHiddenComment.php',
|
||||||
'DifferentialHostField' => 'applications/differential/customfield/DifferentialHostField.php',
|
'DifferentialHostField' => 'applications/differential/customfield/DifferentialHostField.php',
|
||||||
'DifferentialHostedGitLandingStrategy' => 'applications/differential/landing/DifferentialHostedGitLandingStrategy.php',
|
|
||||||
'DifferentialHostedMercurialLandingStrategy' => 'applications/differential/landing/DifferentialHostedMercurialLandingStrategy.php',
|
|
||||||
'DifferentialHovercardEngineExtension' => 'applications/differential/engineextension/DifferentialHovercardEngineExtension.php',
|
'DifferentialHovercardEngineExtension' => 'applications/differential/engineextension/DifferentialHovercardEngineExtension.php',
|
||||||
'DifferentialHunk' => 'applications/differential/storage/DifferentialHunk.php',
|
'DifferentialHunk' => 'applications/differential/storage/DifferentialHunk.php',
|
||||||
'DifferentialHunkParser' => 'applications/differential/parser/DifferentialHunkParser.php',
|
'DifferentialHunkParser' => 'applications/differential/parser/DifferentialHunkParser.php',
|
||||||
|
@ -472,8 +469,6 @@ phutil_register_library_map(array(
|
||||||
'DifferentialInlineCommentQuery' => 'applications/differential/query/DifferentialInlineCommentQuery.php',
|
'DifferentialInlineCommentQuery' => 'applications/differential/query/DifferentialInlineCommentQuery.php',
|
||||||
'DifferentialJIRAIssuesCommitMessageField' => 'applications/differential/field/DifferentialJIRAIssuesCommitMessageField.php',
|
'DifferentialJIRAIssuesCommitMessageField' => 'applications/differential/field/DifferentialJIRAIssuesCommitMessageField.php',
|
||||||
'DifferentialJIRAIssuesField' => 'applications/differential/customfield/DifferentialJIRAIssuesField.php',
|
'DifferentialJIRAIssuesField' => 'applications/differential/customfield/DifferentialJIRAIssuesField.php',
|
||||||
'DifferentialLandingActionMenuEventListener' => 'applications/differential/landing/DifferentialLandingActionMenuEventListener.php',
|
|
||||||
'DifferentialLandingStrategy' => 'applications/differential/landing/DifferentialLandingStrategy.php',
|
|
||||||
'DifferentialLegacyHunk' => 'applications/differential/storage/DifferentialLegacyHunk.php',
|
'DifferentialLegacyHunk' => 'applications/differential/storage/DifferentialLegacyHunk.php',
|
||||||
'DifferentialLineAdjustmentMap' => 'applications/differential/parser/DifferentialLineAdjustmentMap.php',
|
'DifferentialLineAdjustmentMap' => 'applications/differential/parser/DifferentialLineAdjustmentMap.php',
|
||||||
'DifferentialLintField' => 'applications/differential/customfield/DifferentialLintField.php',
|
'DifferentialLintField' => 'applications/differential/customfield/DifferentialLintField.php',
|
||||||
|
@ -547,7 +542,7 @@ phutil_register_library_map(array(
|
||||||
'DifferentialRevisionHeraldField' => 'applications/differential/herald/DifferentialRevisionHeraldField.php',
|
'DifferentialRevisionHeraldField' => 'applications/differential/herald/DifferentialRevisionHeraldField.php',
|
||||||
'DifferentialRevisionHeraldFieldGroup' => 'applications/differential/herald/DifferentialRevisionHeraldFieldGroup.php',
|
'DifferentialRevisionHeraldFieldGroup' => 'applications/differential/herald/DifferentialRevisionHeraldFieldGroup.php',
|
||||||
'DifferentialRevisionIDCommitMessageField' => 'applications/differential/field/DifferentialRevisionIDCommitMessageField.php',
|
'DifferentialRevisionIDCommitMessageField' => 'applications/differential/field/DifferentialRevisionIDCommitMessageField.php',
|
||||||
'DifferentialRevisionLandController' => 'applications/differential/controller/DifferentialRevisionLandController.php',
|
'DifferentialRevisionInlinesController' => 'applications/differential/controller/DifferentialRevisionInlinesController.php',
|
||||||
'DifferentialRevisionListController' => 'applications/differential/controller/DifferentialRevisionListController.php',
|
'DifferentialRevisionListController' => 'applications/differential/controller/DifferentialRevisionListController.php',
|
||||||
'DifferentialRevisionListView' => 'applications/differential/view/DifferentialRevisionListView.php',
|
'DifferentialRevisionListView' => 'applications/differential/view/DifferentialRevisionListView.php',
|
||||||
'DifferentialRevisionMailReceiver' => 'applications/differential/mail/DifferentialRevisionMailReceiver.php',
|
'DifferentialRevisionMailReceiver' => 'applications/differential/mail/DifferentialRevisionMailReceiver.php',
|
||||||
|
@ -612,6 +607,7 @@ phutil_register_library_map(array(
|
||||||
'DiffusionBlameConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionBlameConduitAPIMethod.php',
|
'DiffusionBlameConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionBlameConduitAPIMethod.php',
|
||||||
'DiffusionBlameQuery' => 'applications/diffusion/query/blame/DiffusionBlameQuery.php',
|
'DiffusionBlameQuery' => 'applications/diffusion/query/blame/DiffusionBlameQuery.php',
|
||||||
'DiffusionBlockHeraldAction' => 'applications/diffusion/herald/DiffusionBlockHeraldAction.php',
|
'DiffusionBlockHeraldAction' => 'applications/diffusion/herald/DiffusionBlockHeraldAction.php',
|
||||||
|
'DiffusionBranchListView' => 'applications/diffusion/view/DiffusionBranchListView.php',
|
||||||
'DiffusionBranchQueryConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionBranchQueryConduitAPIMethod.php',
|
'DiffusionBranchQueryConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionBranchQueryConduitAPIMethod.php',
|
||||||
'DiffusionBranchTableController' => 'applications/diffusion/controller/DiffusionBranchTableController.php',
|
'DiffusionBranchTableController' => 'applications/diffusion/controller/DiffusionBranchTableController.php',
|
||||||
'DiffusionBranchTableView' => 'applications/diffusion/view/DiffusionBranchTableView.php',
|
'DiffusionBranchTableView' => 'applications/diffusion/view/DiffusionBranchTableView.php',
|
||||||
|
@ -727,6 +723,7 @@ phutil_register_library_map(array(
|
||||||
'DiffusionGitResponse' => 'applications/diffusion/response/DiffusionGitResponse.php',
|
'DiffusionGitResponse' => 'applications/diffusion/response/DiffusionGitResponse.php',
|
||||||
'DiffusionGitSSHWorkflow' => 'applications/diffusion/ssh/DiffusionGitSSHWorkflow.php',
|
'DiffusionGitSSHWorkflow' => 'applications/diffusion/ssh/DiffusionGitSSHWorkflow.php',
|
||||||
'DiffusionGitUploadPackSSHWorkflow' => 'applications/diffusion/ssh/DiffusionGitUploadPackSSHWorkflow.php',
|
'DiffusionGitUploadPackSSHWorkflow' => 'applications/diffusion/ssh/DiffusionGitUploadPackSSHWorkflow.php',
|
||||||
|
'DiffusionGraphController' => 'applications/diffusion/controller/DiffusionGraphController.php',
|
||||||
'DiffusionHistoryController' => 'applications/diffusion/controller/DiffusionHistoryController.php',
|
'DiffusionHistoryController' => 'applications/diffusion/controller/DiffusionHistoryController.php',
|
||||||
'DiffusionHistoryListView' => 'applications/diffusion/view/DiffusionHistoryListView.php',
|
'DiffusionHistoryListView' => 'applications/diffusion/view/DiffusionHistoryListView.php',
|
||||||
'DiffusionHistoryQueryConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionHistoryQueryConduitAPIMethod.php',
|
'DiffusionHistoryQueryConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionHistoryQueryConduitAPIMethod.php',
|
||||||
|
@ -850,6 +847,7 @@ phutil_register_library_map(array(
|
||||||
'DiffusionRepositoryManagementPanel' => 'applications/diffusion/management/DiffusionRepositoryManagementPanel.php',
|
'DiffusionRepositoryManagementPanel' => 'applications/diffusion/management/DiffusionRepositoryManagementPanel.php',
|
||||||
'DiffusionRepositoryPath' => 'applications/diffusion/data/DiffusionRepositoryPath.php',
|
'DiffusionRepositoryPath' => 'applications/diffusion/data/DiffusionRepositoryPath.php',
|
||||||
'DiffusionRepositoryPoliciesManagementPanel' => 'applications/diffusion/management/DiffusionRepositoryPoliciesManagementPanel.php',
|
'DiffusionRepositoryPoliciesManagementPanel' => 'applications/diffusion/management/DiffusionRepositoryPoliciesManagementPanel.php',
|
||||||
|
'DiffusionRepositoryProfilePictureController' => 'applications/diffusion/controller/DiffusionRepositoryProfilePictureController.php',
|
||||||
'DiffusionRepositoryRef' => 'applications/diffusion/data/DiffusionRepositoryRef.php',
|
'DiffusionRepositoryRef' => 'applications/diffusion/data/DiffusionRepositoryRef.php',
|
||||||
'DiffusionRepositoryRemarkupRule' => 'applications/diffusion/remarkup/DiffusionRepositoryRemarkupRule.php',
|
'DiffusionRepositoryRemarkupRule' => 'applications/diffusion/remarkup/DiffusionRepositoryRemarkupRule.php',
|
||||||
'DiffusionRepositorySearchConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionRepositorySearchConduitAPIMethod.php',
|
'DiffusionRepositorySearchConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionRepositorySearchConduitAPIMethod.php',
|
||||||
|
@ -889,6 +887,7 @@ phutil_register_library_map(array(
|
||||||
'DiffusionSymbolQuery' => 'applications/diffusion/query/DiffusionSymbolQuery.php',
|
'DiffusionSymbolQuery' => 'applications/diffusion/query/DiffusionSymbolQuery.php',
|
||||||
'DiffusionTagListController' => 'applications/diffusion/controller/DiffusionTagListController.php',
|
'DiffusionTagListController' => 'applications/diffusion/controller/DiffusionTagListController.php',
|
||||||
'DiffusionTagListView' => 'applications/diffusion/view/DiffusionTagListView.php',
|
'DiffusionTagListView' => 'applications/diffusion/view/DiffusionTagListView.php',
|
||||||
|
'DiffusionTagTableView' => 'applications/diffusion/view/DiffusionTagTableView.php',
|
||||||
'DiffusionTaggedRepositoriesFunctionDatasource' => 'applications/diffusion/typeahead/DiffusionTaggedRepositoriesFunctionDatasource.php',
|
'DiffusionTaggedRepositoriesFunctionDatasource' => 'applications/diffusion/typeahead/DiffusionTaggedRepositoriesFunctionDatasource.php',
|
||||||
'DiffusionTagsQueryConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionTagsQueryConduitAPIMethod.php',
|
'DiffusionTagsQueryConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionTagsQueryConduitAPIMethod.php',
|
||||||
'DiffusionURIEditConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionURIEditConduitAPIMethod.php',
|
'DiffusionURIEditConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionURIEditConduitAPIMethod.php',
|
||||||
|
@ -1503,6 +1502,7 @@ phutil_register_library_map(array(
|
||||||
'ManiphestSearchConduitAPIMethod' => 'applications/maniphest/conduit/ManiphestSearchConduitAPIMethod.php',
|
'ManiphestSearchConduitAPIMethod' => 'applications/maniphest/conduit/ManiphestSearchConduitAPIMethod.php',
|
||||||
'ManiphestStatusConfigOptionType' => 'applications/maniphest/config/ManiphestStatusConfigOptionType.php',
|
'ManiphestStatusConfigOptionType' => 'applications/maniphest/config/ManiphestStatusConfigOptionType.php',
|
||||||
'ManiphestStatusEmailCommand' => 'applications/maniphest/command/ManiphestStatusEmailCommand.php',
|
'ManiphestStatusEmailCommand' => 'applications/maniphest/command/ManiphestStatusEmailCommand.php',
|
||||||
|
'ManiphestStatusSearchConduitAPIMethod' => 'applications/maniphest/conduit/ManiphestStatusSearchConduitAPIMethod.php',
|
||||||
'ManiphestSubpriorityController' => 'applications/maniphest/controller/ManiphestSubpriorityController.php',
|
'ManiphestSubpriorityController' => 'applications/maniphest/controller/ManiphestSubpriorityController.php',
|
||||||
'ManiphestSubtypesConfigOptionsType' => 'applications/maniphest/config/ManiphestSubtypesConfigOptionsType.php',
|
'ManiphestSubtypesConfigOptionsType' => 'applications/maniphest/config/ManiphestSubtypesConfigOptionsType.php',
|
||||||
'ManiphestTask' => 'applications/maniphest/storage/ManiphestTask.php',
|
'ManiphestTask' => 'applications/maniphest/storage/ManiphestTask.php',
|
||||||
|
@ -1737,6 +1737,7 @@ phutil_register_library_map(array(
|
||||||
'PHUIDiffInlineCommentTableScaffold' => 'infrastructure/diff/view/PHUIDiffInlineCommentTableScaffold.php',
|
'PHUIDiffInlineCommentTableScaffold' => 'infrastructure/diff/view/PHUIDiffInlineCommentTableScaffold.php',
|
||||||
'PHUIDiffInlineCommentUndoView' => 'infrastructure/diff/view/PHUIDiffInlineCommentUndoView.php',
|
'PHUIDiffInlineCommentUndoView' => 'infrastructure/diff/view/PHUIDiffInlineCommentUndoView.php',
|
||||||
'PHUIDiffInlineCommentView' => 'infrastructure/diff/view/PHUIDiffInlineCommentView.php',
|
'PHUIDiffInlineCommentView' => 'infrastructure/diff/view/PHUIDiffInlineCommentView.php',
|
||||||
|
'PHUIDiffInlineThreader' => 'infrastructure/diff/view/PHUIDiffInlineThreader.php',
|
||||||
'PHUIDiffOneUpInlineCommentRowScaffold' => 'infrastructure/diff/view/PHUIDiffOneUpInlineCommentRowScaffold.php',
|
'PHUIDiffOneUpInlineCommentRowScaffold' => 'infrastructure/diff/view/PHUIDiffOneUpInlineCommentRowScaffold.php',
|
||||||
'PHUIDiffRevealIconView' => 'infrastructure/diff/view/PHUIDiffRevealIconView.php',
|
'PHUIDiffRevealIconView' => 'infrastructure/diff/view/PHUIDiffRevealIconView.php',
|
||||||
'PHUIDiffTableOfContentsItemView' => 'infrastructure/diff/view/PHUIDiffTableOfContentsItemView.php',
|
'PHUIDiffTableOfContentsItemView' => 'infrastructure/diff/view/PHUIDiffTableOfContentsItemView.php',
|
||||||
|
@ -2155,6 +2156,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorBoolEditField' => 'applications/transactions/editfield/PhabricatorBoolEditField.php',
|
'PhabricatorBoolEditField' => 'applications/transactions/editfield/PhabricatorBoolEditField.php',
|
||||||
'PhabricatorBritishEnglishTranslation' => 'infrastructure/internationalization/translation/PhabricatorBritishEnglishTranslation.php',
|
'PhabricatorBritishEnglishTranslation' => 'infrastructure/internationalization/translation/PhabricatorBritishEnglishTranslation.php',
|
||||||
'PhabricatorBuiltinDraftEngine' => 'applications/transactions/draft/PhabricatorBuiltinDraftEngine.php',
|
'PhabricatorBuiltinDraftEngine' => 'applications/transactions/draft/PhabricatorBuiltinDraftEngine.php',
|
||||||
|
'PhabricatorBuiltinFileCachePurger' => 'applications/cache/purger/PhabricatorBuiltinFileCachePurger.php',
|
||||||
'PhabricatorBuiltinPatchList' => 'infrastructure/storage/patch/PhabricatorBuiltinPatchList.php',
|
'PhabricatorBuiltinPatchList' => 'infrastructure/storage/patch/PhabricatorBuiltinPatchList.php',
|
||||||
'PhabricatorBulkContentSource' => 'infrastructure/daemon/contentsource/PhabricatorBulkContentSource.php',
|
'PhabricatorBulkContentSource' => 'infrastructure/daemon/contentsource/PhabricatorBulkContentSource.php',
|
||||||
'PhabricatorCacheDAO' => 'applications/cache/storage/PhabricatorCacheDAO.php',
|
'PhabricatorCacheDAO' => 'applications/cache/storage/PhabricatorCacheDAO.php',
|
||||||
|
@ -2164,6 +2166,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorCacheManagementPurgeWorkflow' => 'applications/cache/management/PhabricatorCacheManagementPurgeWorkflow.php',
|
'PhabricatorCacheManagementPurgeWorkflow' => 'applications/cache/management/PhabricatorCacheManagementPurgeWorkflow.php',
|
||||||
'PhabricatorCacheManagementWorkflow' => 'applications/cache/management/PhabricatorCacheManagementWorkflow.php',
|
'PhabricatorCacheManagementWorkflow' => 'applications/cache/management/PhabricatorCacheManagementWorkflow.php',
|
||||||
'PhabricatorCacheMarkupGarbageCollector' => 'applications/cache/garbagecollector/PhabricatorCacheMarkupGarbageCollector.php',
|
'PhabricatorCacheMarkupGarbageCollector' => 'applications/cache/garbagecollector/PhabricatorCacheMarkupGarbageCollector.php',
|
||||||
|
'PhabricatorCachePurger' => 'applications/cache/purger/PhabricatorCachePurger.php',
|
||||||
'PhabricatorCacheSchemaSpec' => 'applications/cache/storage/PhabricatorCacheSchemaSpec.php',
|
'PhabricatorCacheSchemaSpec' => 'applications/cache/storage/PhabricatorCacheSchemaSpec.php',
|
||||||
'PhabricatorCacheSetupCheck' => 'applications/config/check/PhabricatorCacheSetupCheck.php',
|
'PhabricatorCacheSetupCheck' => 'applications/config/check/PhabricatorCacheSetupCheck.php',
|
||||||
'PhabricatorCacheSpec' => 'applications/cache/spec/PhabricatorCacheSpec.php',
|
'PhabricatorCacheSpec' => 'applications/cache/spec/PhabricatorCacheSpec.php',
|
||||||
|
@ -2313,6 +2316,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorCelerityApplication' => 'applications/celerity/application/PhabricatorCelerityApplication.php',
|
'PhabricatorCelerityApplication' => 'applications/celerity/application/PhabricatorCelerityApplication.php',
|
||||||
'PhabricatorCelerityTestCase' => '__tests__/PhabricatorCelerityTestCase.php',
|
'PhabricatorCelerityTestCase' => '__tests__/PhabricatorCelerityTestCase.php',
|
||||||
'PhabricatorChangeParserTestCase' => 'applications/repository/worker/__tests__/PhabricatorChangeParserTestCase.php',
|
'PhabricatorChangeParserTestCase' => 'applications/repository/worker/__tests__/PhabricatorChangeParserTestCase.php',
|
||||||
|
'PhabricatorChangesetCachePurger' => 'applications/cache/purger/PhabricatorChangesetCachePurger.php',
|
||||||
'PhabricatorChangesetResponse' => 'infrastructure/diff/PhabricatorChangesetResponse.php',
|
'PhabricatorChangesetResponse' => 'infrastructure/diff/PhabricatorChangesetResponse.php',
|
||||||
'PhabricatorChatLogApplication' => 'applications/chatlog/application/PhabricatorChatLogApplication.php',
|
'PhabricatorChatLogApplication' => 'applications/chatlog/application/PhabricatorChatLogApplication.php',
|
||||||
'PhabricatorChatLogChannel' => 'applications/chatlog/storage/PhabricatorChatLogChannel.php',
|
'PhabricatorChatLogChannel' => 'applications/chatlog/storage/PhabricatorChatLogChannel.php',
|
||||||
|
@ -2923,6 +2927,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorGarbageCollectorManagementCollectWorkflow' => 'infrastructure/daemon/garbagecollector/management/PhabricatorGarbageCollectorManagementCollectWorkflow.php',
|
'PhabricatorGarbageCollectorManagementCollectWorkflow' => 'infrastructure/daemon/garbagecollector/management/PhabricatorGarbageCollectorManagementCollectWorkflow.php',
|
||||||
'PhabricatorGarbageCollectorManagementSetPolicyWorkflow' => 'infrastructure/daemon/garbagecollector/management/PhabricatorGarbageCollectorManagementSetPolicyWorkflow.php',
|
'PhabricatorGarbageCollectorManagementSetPolicyWorkflow' => 'infrastructure/daemon/garbagecollector/management/PhabricatorGarbageCollectorManagementSetPolicyWorkflow.php',
|
||||||
'PhabricatorGarbageCollectorManagementWorkflow' => 'infrastructure/daemon/garbagecollector/management/PhabricatorGarbageCollectorManagementWorkflow.php',
|
'PhabricatorGarbageCollectorManagementWorkflow' => 'infrastructure/daemon/garbagecollector/management/PhabricatorGarbageCollectorManagementWorkflow.php',
|
||||||
|
'PhabricatorGeneralCachePurger' => 'applications/cache/purger/PhabricatorGeneralCachePurger.php',
|
||||||
'PhabricatorGestureUIExample' => 'applications/uiexample/examples/PhabricatorGestureUIExample.php',
|
'PhabricatorGestureUIExample' => 'applications/uiexample/examples/PhabricatorGestureUIExample.php',
|
||||||
'PhabricatorGitGraphStream' => 'applications/repository/daemon/PhabricatorGitGraphStream.php',
|
'PhabricatorGitGraphStream' => 'applications/repository/daemon/PhabricatorGitGraphStream.php',
|
||||||
'PhabricatorGitHubAuthProvider' => 'applications/auth/provider/PhabricatorGitHubAuthProvider.php',
|
'PhabricatorGitHubAuthProvider' => 'applications/auth/provider/PhabricatorGitHubAuthProvider.php',
|
||||||
|
@ -3741,6 +3746,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorRegistrationProfile' => 'applications/people/storage/PhabricatorRegistrationProfile.php',
|
'PhabricatorRegistrationProfile' => 'applications/people/storage/PhabricatorRegistrationProfile.php',
|
||||||
'PhabricatorReleephApplication' => 'applications/releeph/application/PhabricatorReleephApplication.php',
|
'PhabricatorReleephApplication' => 'applications/releeph/application/PhabricatorReleephApplication.php',
|
||||||
'PhabricatorReleephApplicationConfigOptions' => 'applications/releeph/config/PhabricatorReleephApplicationConfigOptions.php',
|
'PhabricatorReleephApplicationConfigOptions' => 'applications/releeph/config/PhabricatorReleephApplicationConfigOptions.php',
|
||||||
|
'PhabricatorRemarkupCachePurger' => 'applications/cache/purger/PhabricatorRemarkupCachePurger.php',
|
||||||
'PhabricatorRemarkupControl' => 'view/form/control/PhabricatorRemarkupControl.php',
|
'PhabricatorRemarkupControl' => 'view/form/control/PhabricatorRemarkupControl.php',
|
||||||
'PhabricatorRemarkupCowsayBlockInterpreter' => 'infrastructure/markup/interpreter/PhabricatorRemarkupCowsayBlockInterpreter.php',
|
'PhabricatorRemarkupCowsayBlockInterpreter' => 'infrastructure/markup/interpreter/PhabricatorRemarkupCowsayBlockInterpreter.php',
|
||||||
'PhabricatorRemarkupCustomBlockRule' => 'infrastructure/markup/rule/PhabricatorRemarkupCustomBlockRule.php',
|
'PhabricatorRemarkupCustomBlockRule' => 'infrastructure/markup/rule/PhabricatorRemarkupCustomBlockRule.php',
|
||||||
|
@ -4195,6 +4201,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorUserBadgesCacheType' => 'applications/people/cache/PhabricatorUserBadgesCacheType.php',
|
'PhabricatorUserBadgesCacheType' => 'applications/people/cache/PhabricatorUserBadgesCacheType.php',
|
||||||
'PhabricatorUserBlurbField' => 'applications/people/customfield/PhabricatorUserBlurbField.php',
|
'PhabricatorUserBlurbField' => 'applications/people/customfield/PhabricatorUserBlurbField.php',
|
||||||
'PhabricatorUserCache' => 'applications/people/storage/PhabricatorUserCache.php',
|
'PhabricatorUserCache' => 'applications/people/storage/PhabricatorUserCache.php',
|
||||||
|
'PhabricatorUserCachePurger' => 'applications/cache/purger/PhabricatorUserCachePurger.php',
|
||||||
'PhabricatorUserCacheType' => 'applications/people/cache/PhabricatorUserCacheType.php',
|
'PhabricatorUserCacheType' => 'applications/people/cache/PhabricatorUserCacheType.php',
|
||||||
'PhabricatorUserCardView' => 'applications/people/view/PhabricatorUserCardView.php',
|
'PhabricatorUserCardView' => 'applications/people/view/PhabricatorUserCardView.php',
|
||||||
'PhabricatorUserConfigOptions' => 'applications/people/config/PhabricatorUserConfigOptions.php',
|
'PhabricatorUserConfigOptions' => 'applications/people/config/PhabricatorUserConfigOptions.php',
|
||||||
|
@ -5398,13 +5405,10 @@ phutil_register_library_map(array(
|
||||||
'DifferentialGetRevisionCommentsConduitAPIMethod' => 'DifferentialConduitAPIMethod',
|
'DifferentialGetRevisionCommentsConduitAPIMethod' => 'DifferentialConduitAPIMethod',
|
||||||
'DifferentialGetRevisionConduitAPIMethod' => 'DifferentialConduitAPIMethod',
|
'DifferentialGetRevisionConduitAPIMethod' => 'DifferentialConduitAPIMethod',
|
||||||
'DifferentialGetWorkingCopy' => 'Phobject',
|
'DifferentialGetWorkingCopy' => 'Phobject',
|
||||||
'DifferentialGitHubLandingStrategy' => 'DifferentialLandingStrategy',
|
|
||||||
'DifferentialGitSVNIDCommitMessageField' => 'DifferentialCommitMessageField',
|
'DifferentialGitSVNIDCommitMessageField' => 'DifferentialCommitMessageField',
|
||||||
'DifferentialHarbormasterField' => 'DifferentialCustomField',
|
'DifferentialHarbormasterField' => 'DifferentialCustomField',
|
||||||
'DifferentialHiddenComment' => 'DifferentialDAO',
|
'DifferentialHiddenComment' => 'DifferentialDAO',
|
||||||
'DifferentialHostField' => 'DifferentialCustomField',
|
'DifferentialHostField' => 'DifferentialCustomField',
|
||||||
'DifferentialHostedGitLandingStrategy' => 'DifferentialLandingStrategy',
|
|
||||||
'DifferentialHostedMercurialLandingStrategy' => 'DifferentialLandingStrategy',
|
|
||||||
'DifferentialHovercardEngineExtension' => 'PhabricatorHovercardEngineExtension',
|
'DifferentialHovercardEngineExtension' => 'PhabricatorHovercardEngineExtension',
|
||||||
'DifferentialHunk' => array(
|
'DifferentialHunk' => array(
|
||||||
'DifferentialDAO',
|
'DifferentialDAO',
|
||||||
|
@ -5423,8 +5427,6 @@ phutil_register_library_map(array(
|
||||||
'DifferentialInlineCommentQuery' => 'PhabricatorOffsetPagedQuery',
|
'DifferentialInlineCommentQuery' => 'PhabricatorOffsetPagedQuery',
|
||||||
'DifferentialJIRAIssuesCommitMessageField' => 'DifferentialCommitMessageCustomField',
|
'DifferentialJIRAIssuesCommitMessageField' => 'DifferentialCommitMessageCustomField',
|
||||||
'DifferentialJIRAIssuesField' => 'DifferentialStoredCustomField',
|
'DifferentialJIRAIssuesField' => 'DifferentialStoredCustomField',
|
||||||
'DifferentialLandingActionMenuEventListener' => 'PhabricatorEventListener',
|
|
||||||
'DifferentialLandingStrategy' => 'Phobject',
|
|
||||||
'DifferentialLegacyHunk' => 'DifferentialHunk',
|
'DifferentialLegacyHunk' => 'DifferentialHunk',
|
||||||
'DifferentialLineAdjustmentMap' => 'Phobject',
|
'DifferentialLineAdjustmentMap' => 'Phobject',
|
||||||
'DifferentialLintField' => 'DifferentialHarbormasterField',
|
'DifferentialLintField' => 'DifferentialHarbormasterField',
|
||||||
|
@ -5515,7 +5517,7 @@ phutil_register_library_map(array(
|
||||||
'DifferentialRevisionHeraldField' => 'HeraldField',
|
'DifferentialRevisionHeraldField' => 'HeraldField',
|
||||||
'DifferentialRevisionHeraldFieldGroup' => 'HeraldFieldGroup',
|
'DifferentialRevisionHeraldFieldGroup' => 'HeraldFieldGroup',
|
||||||
'DifferentialRevisionIDCommitMessageField' => 'DifferentialCommitMessageField',
|
'DifferentialRevisionIDCommitMessageField' => 'DifferentialCommitMessageField',
|
||||||
'DifferentialRevisionLandController' => 'DifferentialController',
|
'DifferentialRevisionInlinesController' => 'DifferentialController',
|
||||||
'DifferentialRevisionListController' => 'DifferentialController',
|
'DifferentialRevisionListController' => 'DifferentialController',
|
||||||
'DifferentialRevisionListView' => 'AphrontView',
|
'DifferentialRevisionListView' => 'AphrontView',
|
||||||
'DifferentialRevisionMailReceiver' => 'PhabricatorObjectMailReceiver',
|
'DifferentialRevisionMailReceiver' => 'PhabricatorObjectMailReceiver',
|
||||||
|
@ -5580,6 +5582,7 @@ phutil_register_library_map(array(
|
||||||
'DiffusionBlameConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod',
|
'DiffusionBlameConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod',
|
||||||
'DiffusionBlameQuery' => 'DiffusionQuery',
|
'DiffusionBlameQuery' => 'DiffusionQuery',
|
||||||
'DiffusionBlockHeraldAction' => 'HeraldAction',
|
'DiffusionBlockHeraldAction' => 'HeraldAction',
|
||||||
|
'DiffusionBranchListView' => 'DiffusionView',
|
||||||
'DiffusionBranchQueryConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod',
|
'DiffusionBranchQueryConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod',
|
||||||
'DiffusionBranchTableController' => 'DiffusionController',
|
'DiffusionBranchTableController' => 'DiffusionController',
|
||||||
'DiffusionBranchTableView' => 'DiffusionView',
|
'DiffusionBranchTableView' => 'DiffusionView',
|
||||||
|
@ -5698,6 +5701,7 @@ phutil_register_library_map(array(
|
||||||
'DiffusionRepositoryClusterEngineLogInterface',
|
'DiffusionRepositoryClusterEngineLogInterface',
|
||||||
),
|
),
|
||||||
'DiffusionGitUploadPackSSHWorkflow' => 'DiffusionGitSSHWorkflow',
|
'DiffusionGitUploadPackSSHWorkflow' => 'DiffusionGitSSHWorkflow',
|
||||||
|
'DiffusionGraphController' => 'DiffusionController',
|
||||||
'DiffusionHistoryController' => 'DiffusionController',
|
'DiffusionHistoryController' => 'DiffusionController',
|
||||||
'DiffusionHistoryListView' => 'DiffusionHistoryView',
|
'DiffusionHistoryListView' => 'DiffusionHistoryView',
|
||||||
'DiffusionHistoryQueryConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod',
|
'DiffusionHistoryQueryConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod',
|
||||||
|
@ -5820,6 +5824,7 @@ phutil_register_library_map(array(
|
||||||
'DiffusionRepositoryManagementPanel' => 'Phobject',
|
'DiffusionRepositoryManagementPanel' => 'Phobject',
|
||||||
'DiffusionRepositoryPath' => 'Phobject',
|
'DiffusionRepositoryPath' => 'Phobject',
|
||||||
'DiffusionRepositoryPoliciesManagementPanel' => 'DiffusionRepositoryManagementPanel',
|
'DiffusionRepositoryPoliciesManagementPanel' => 'DiffusionRepositoryManagementPanel',
|
||||||
|
'DiffusionRepositoryProfilePictureController' => 'DiffusionController',
|
||||||
'DiffusionRepositoryRef' => 'Phobject',
|
'DiffusionRepositoryRef' => 'Phobject',
|
||||||
'DiffusionRepositoryRemarkupRule' => 'PhabricatorObjectRemarkupRule',
|
'DiffusionRepositoryRemarkupRule' => 'PhabricatorObjectRemarkupRule',
|
||||||
'DiffusionRepositorySearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod',
|
'DiffusionRepositorySearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod',
|
||||||
|
@ -5859,6 +5864,7 @@ phutil_register_library_map(array(
|
||||||
'DiffusionSymbolQuery' => 'PhabricatorOffsetPagedQuery',
|
'DiffusionSymbolQuery' => 'PhabricatorOffsetPagedQuery',
|
||||||
'DiffusionTagListController' => 'DiffusionController',
|
'DiffusionTagListController' => 'DiffusionController',
|
||||||
'DiffusionTagListView' => 'DiffusionView',
|
'DiffusionTagListView' => 'DiffusionView',
|
||||||
|
'DiffusionTagTableView' => 'DiffusionView',
|
||||||
'DiffusionTaggedRepositoriesFunctionDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
|
'DiffusionTaggedRepositoriesFunctionDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
|
||||||
'DiffusionTagsQueryConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod',
|
'DiffusionTagsQueryConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod',
|
||||||
'DiffusionURIEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod',
|
'DiffusionURIEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod',
|
||||||
|
@ -6598,6 +6604,7 @@ phutil_register_library_map(array(
|
||||||
'ManiphestSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod',
|
'ManiphestSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod',
|
||||||
'ManiphestStatusConfigOptionType' => 'PhabricatorConfigJSONOptionType',
|
'ManiphestStatusConfigOptionType' => 'PhabricatorConfigJSONOptionType',
|
||||||
'ManiphestStatusEmailCommand' => 'ManiphestEmailCommand',
|
'ManiphestStatusEmailCommand' => 'ManiphestEmailCommand',
|
||||||
|
'ManiphestStatusSearchConduitAPIMethod' => 'ManiphestConduitAPIMethod',
|
||||||
'ManiphestSubpriorityController' => 'ManiphestController',
|
'ManiphestSubpriorityController' => 'ManiphestController',
|
||||||
'ManiphestSubtypesConfigOptionsType' => 'PhabricatorConfigJSONOptionType',
|
'ManiphestSubtypesConfigOptionsType' => 'PhabricatorConfigJSONOptionType',
|
||||||
'ManiphestTask' => array(
|
'ManiphestTask' => array(
|
||||||
|
@ -6870,6 +6877,7 @@ phutil_register_library_map(array(
|
||||||
'PHUIDiffInlineCommentTableScaffold' => 'AphrontView',
|
'PHUIDiffInlineCommentTableScaffold' => 'AphrontView',
|
||||||
'PHUIDiffInlineCommentUndoView' => 'PHUIDiffInlineCommentView',
|
'PHUIDiffInlineCommentUndoView' => 'PHUIDiffInlineCommentView',
|
||||||
'PHUIDiffInlineCommentView' => 'AphrontView',
|
'PHUIDiffInlineCommentView' => 'AphrontView',
|
||||||
|
'PHUIDiffInlineThreader' => 'Phobject',
|
||||||
'PHUIDiffOneUpInlineCommentRowScaffold' => 'PHUIDiffInlineCommentRowScaffold',
|
'PHUIDiffOneUpInlineCommentRowScaffold' => 'PHUIDiffInlineCommentRowScaffold',
|
||||||
'PHUIDiffRevealIconView' => 'AphrontView',
|
'PHUIDiffRevealIconView' => 'AphrontView',
|
||||||
'PHUIDiffTableOfContentsItemView' => 'AphrontView',
|
'PHUIDiffTableOfContentsItemView' => 'AphrontView',
|
||||||
|
@ -7343,6 +7351,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorBoolEditField' => 'PhabricatorEditField',
|
'PhabricatorBoolEditField' => 'PhabricatorEditField',
|
||||||
'PhabricatorBritishEnglishTranslation' => 'PhutilTranslation',
|
'PhabricatorBritishEnglishTranslation' => 'PhutilTranslation',
|
||||||
'PhabricatorBuiltinDraftEngine' => 'PhabricatorDraftEngine',
|
'PhabricatorBuiltinDraftEngine' => 'PhabricatorDraftEngine',
|
||||||
|
'PhabricatorBuiltinFileCachePurger' => 'PhabricatorCachePurger',
|
||||||
'PhabricatorBuiltinPatchList' => 'PhabricatorSQLPatchList',
|
'PhabricatorBuiltinPatchList' => 'PhabricatorSQLPatchList',
|
||||||
'PhabricatorBulkContentSource' => 'PhabricatorContentSource',
|
'PhabricatorBulkContentSource' => 'PhabricatorContentSource',
|
||||||
'PhabricatorCacheDAO' => 'PhabricatorLiskDAO',
|
'PhabricatorCacheDAO' => 'PhabricatorLiskDAO',
|
||||||
|
@ -7352,6 +7361,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorCacheManagementPurgeWorkflow' => 'PhabricatorCacheManagementWorkflow',
|
'PhabricatorCacheManagementPurgeWorkflow' => 'PhabricatorCacheManagementWorkflow',
|
||||||
'PhabricatorCacheManagementWorkflow' => 'PhabricatorManagementWorkflow',
|
'PhabricatorCacheManagementWorkflow' => 'PhabricatorManagementWorkflow',
|
||||||
'PhabricatorCacheMarkupGarbageCollector' => 'PhabricatorGarbageCollector',
|
'PhabricatorCacheMarkupGarbageCollector' => 'PhabricatorGarbageCollector',
|
||||||
|
'PhabricatorCachePurger' => 'Phobject',
|
||||||
'PhabricatorCacheSchemaSpec' => 'PhabricatorConfigSchemaSpec',
|
'PhabricatorCacheSchemaSpec' => 'PhabricatorConfigSchemaSpec',
|
||||||
'PhabricatorCacheSetupCheck' => 'PhabricatorSetupCheck',
|
'PhabricatorCacheSetupCheck' => 'PhabricatorSetupCheck',
|
||||||
'PhabricatorCacheSpec' => 'Phobject',
|
'PhabricatorCacheSpec' => 'Phobject',
|
||||||
|
@ -7537,6 +7547,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorCelerityApplication' => 'PhabricatorApplication',
|
'PhabricatorCelerityApplication' => 'PhabricatorApplication',
|
||||||
'PhabricatorCelerityTestCase' => 'PhabricatorTestCase',
|
'PhabricatorCelerityTestCase' => 'PhabricatorTestCase',
|
||||||
'PhabricatorChangeParserTestCase' => 'PhabricatorWorkingCopyTestCase',
|
'PhabricatorChangeParserTestCase' => 'PhabricatorWorkingCopyTestCase',
|
||||||
|
'PhabricatorChangesetCachePurger' => 'PhabricatorCachePurger',
|
||||||
'PhabricatorChangesetResponse' => 'AphrontProxyResponse',
|
'PhabricatorChangesetResponse' => 'AphrontProxyResponse',
|
||||||
'PhabricatorChatLogApplication' => 'PhabricatorApplication',
|
'PhabricatorChatLogApplication' => 'PhabricatorApplication',
|
||||||
'PhabricatorChatLogChannel' => array(
|
'PhabricatorChatLogChannel' => array(
|
||||||
|
@ -8239,6 +8250,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorGarbageCollectorManagementCollectWorkflow' => 'PhabricatorGarbageCollectorManagementWorkflow',
|
'PhabricatorGarbageCollectorManagementCollectWorkflow' => 'PhabricatorGarbageCollectorManagementWorkflow',
|
||||||
'PhabricatorGarbageCollectorManagementSetPolicyWorkflow' => 'PhabricatorGarbageCollectorManagementWorkflow',
|
'PhabricatorGarbageCollectorManagementSetPolicyWorkflow' => 'PhabricatorGarbageCollectorManagementWorkflow',
|
||||||
'PhabricatorGarbageCollectorManagementWorkflow' => 'PhabricatorManagementWorkflow',
|
'PhabricatorGarbageCollectorManagementWorkflow' => 'PhabricatorManagementWorkflow',
|
||||||
|
'PhabricatorGeneralCachePurger' => 'PhabricatorCachePurger',
|
||||||
'PhabricatorGestureUIExample' => 'PhabricatorUIExample',
|
'PhabricatorGestureUIExample' => 'PhabricatorUIExample',
|
||||||
'PhabricatorGitGraphStream' => 'PhabricatorRepositoryGraphStream',
|
'PhabricatorGitGraphStream' => 'PhabricatorRepositoryGraphStream',
|
||||||
'PhabricatorGitHubAuthProvider' => 'PhabricatorOAuth2AuthProvider',
|
'PhabricatorGitHubAuthProvider' => 'PhabricatorOAuth2AuthProvider',
|
||||||
|
@ -9190,6 +9202,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorRegistrationProfile' => 'Phobject',
|
'PhabricatorRegistrationProfile' => 'Phobject',
|
||||||
'PhabricatorReleephApplication' => 'PhabricatorApplication',
|
'PhabricatorReleephApplication' => 'PhabricatorApplication',
|
||||||
'PhabricatorReleephApplicationConfigOptions' => 'PhabricatorApplicationConfigOptions',
|
'PhabricatorReleephApplicationConfigOptions' => 'PhabricatorApplicationConfigOptions',
|
||||||
|
'PhabricatorRemarkupCachePurger' => 'PhabricatorCachePurger',
|
||||||
'PhabricatorRemarkupControl' => 'AphrontFormTextAreaControl',
|
'PhabricatorRemarkupControl' => 'AphrontFormTextAreaControl',
|
||||||
'PhabricatorRemarkupCowsayBlockInterpreter' => 'PhutilRemarkupBlockInterpreter',
|
'PhabricatorRemarkupCowsayBlockInterpreter' => 'PhutilRemarkupBlockInterpreter',
|
||||||
'PhabricatorRemarkupCustomBlockRule' => 'PhutilRemarkupBlockRule',
|
'PhabricatorRemarkupCustomBlockRule' => 'PhutilRemarkupBlockRule',
|
||||||
|
@ -9742,6 +9755,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorUserBadgesCacheType' => 'PhabricatorUserCacheType',
|
'PhabricatorUserBadgesCacheType' => 'PhabricatorUserCacheType',
|
||||||
'PhabricatorUserBlurbField' => 'PhabricatorUserCustomField',
|
'PhabricatorUserBlurbField' => 'PhabricatorUserCustomField',
|
||||||
'PhabricatorUserCache' => 'PhabricatorUserDAO',
|
'PhabricatorUserCache' => 'PhabricatorUserDAO',
|
||||||
|
'PhabricatorUserCachePurger' => 'PhabricatorCachePurger',
|
||||||
'PhabricatorUserCacheType' => 'Phobject',
|
'PhabricatorUserCacheType' => 'Phobject',
|
||||||
'PhabricatorUserCardView' => 'AphrontTagView',
|
'PhabricatorUserCardView' => 'AphrontTagView',
|
||||||
'PhabricatorUserConfigOptions' => 'PhabricatorApplicationConfigOptions',
|
'PhabricatorUserConfigOptions' => 'PhabricatorApplicationConfigOptions',
|
||||||
|
|
|
@ -270,7 +270,10 @@ abstract class AphrontApplicationConfiguration extends Phobject {
|
||||||
}
|
}
|
||||||
} catch (Exception $ex) {
|
} catch (Exception $ex) {
|
||||||
$original_exception = $ex;
|
$original_exception = $ex;
|
||||||
$response = $this->handleException($ex);
|
$response = $this->handleThrowable($ex);
|
||||||
|
} catch (Throwable $ex) {
|
||||||
|
$original_exception = $ex;
|
||||||
|
$response = $this->handleThrowable($ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -663,24 +666,24 @@ abstract class AphrontApplicationConfiguration extends Phobject {
|
||||||
* This method delegates exception handling to available subclasses of
|
* This method delegates exception handling to available subclasses of
|
||||||
* @{class:AphrontRequestExceptionHandler}.
|
* @{class:AphrontRequestExceptionHandler}.
|
||||||
*
|
*
|
||||||
* @param Exception Exception which needs to be handled.
|
* @param Throwable Exception which needs to be handled.
|
||||||
* @return wild Response or response producer, or null if no available
|
* @return wild Response or response producer, or null if no available
|
||||||
* handler can produce a response.
|
* handler can produce a response.
|
||||||
* @task exception
|
* @task exception
|
||||||
*/
|
*/
|
||||||
private function handleException(Exception $ex) {
|
private function handleThrowable($throwable) {
|
||||||
$handlers = AphrontRequestExceptionHandler::getAllHandlers();
|
$handlers = AphrontRequestExceptionHandler::getAllHandlers();
|
||||||
|
|
||||||
$request = $this->getRequest();
|
$request = $this->getRequest();
|
||||||
foreach ($handlers as $handler) {
|
foreach ($handlers as $handler) {
|
||||||
if ($handler->canHandleRequestException($request, $ex)) {
|
if ($handler->canHandleRequestThrowable($request, $throwable)) {
|
||||||
$response = $handler->handleRequestException($request, $ex);
|
$response = $handler->handleRequestThrowable($request, $throwable);
|
||||||
$this->validateErrorHandlerResponse($handler, $response);
|
$this->validateErrorHandlerResponse($handler, $response);
|
||||||
return $response;
|
return $response;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
throw $ex;
|
throw $throwable;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function newSelfCheckResponse() {
|
private static function newSelfCheckResponse() {
|
||||||
|
|
|
@ -12,19 +12,13 @@ abstract class AphrontRequestExceptionHandler extends Phobject {
|
||||||
|
|
||||||
abstract public function getRequestExceptionHandlerPriority();
|
abstract public function getRequestExceptionHandlerPriority();
|
||||||
|
|
||||||
public function shouldLogException(
|
abstract public function canHandleRequestThrowable(
|
||||||
AphrontRequest $request,
|
AphrontRequest $request,
|
||||||
Exception $ex) {
|
$throwable);
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract public function canHandleRequestException(
|
abstract public function handleRequestThrowable(
|
||||||
AphrontRequest $request,
|
AphrontRequest $request,
|
||||||
Exception $ex);
|
$throwable);
|
||||||
|
|
||||||
abstract public function handleRequestException(
|
|
||||||
AphrontRequest $request,
|
|
||||||
Exception $ex);
|
|
||||||
|
|
||||||
final public static function getAllHandlers() {
|
final public static function getAllHandlers() {
|
||||||
return id(new PhutilClassMapQuery())
|
return id(new PhutilClassMapQuery())
|
||||||
|
|
|
@ -11,27 +11,28 @@ final class PhabricatorAjaxRequestExceptionHandler
|
||||||
return pht('Responds to requests made by AJAX clients.');
|
return pht('Responds to requests made by AJAX clients.');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function canHandleRequestException(
|
public function canHandleRequestThrowable(
|
||||||
AphrontRequest $request,
|
AphrontRequest $request,
|
||||||
Exception $ex) {
|
$throwable) {
|
||||||
// For non-workflow requests, return a Ajax response.
|
// For non-workflow requests, return a Ajax response.
|
||||||
return ($request->isAjax() && !$request->isWorkflow());
|
return ($request->isAjax() && !$request->isWorkflow());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handleRequestException(
|
public function handleRequestThrowable(
|
||||||
AphrontRequest $request,
|
AphrontRequest $request,
|
||||||
Exception $ex) {
|
$throwable) {
|
||||||
|
|
||||||
// Log these; they don't get shown on the client and can be difficult
|
// Log these; they don't get shown on the client and can be difficult
|
||||||
// to debug.
|
// to debug.
|
||||||
phlog($ex);
|
phlog($throwable);
|
||||||
|
|
||||||
$response = new AphrontAjaxResponse();
|
$response = new AphrontAjaxResponse();
|
||||||
$response->setError(
|
$response->setError(
|
||||||
array(
|
array(
|
||||||
'code' => get_class($ex),
|
'code' => get_class($throwable),
|
||||||
'info' => $ex->getMessage(),
|
'info' => $throwable->getMessage(),
|
||||||
));
|
));
|
||||||
|
|
||||||
return $response;
|
return $response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,19 +11,19 @@ final class PhabricatorConduitRequestExceptionHandler
|
||||||
return pht('Responds to requests made by Conduit clients.');
|
return pht('Responds to requests made by Conduit clients.');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function canHandleRequestException(
|
public function canHandleRequestThrowable(
|
||||||
AphrontRequest $request,
|
AphrontRequest $request,
|
||||||
Exception $ex) {
|
$throwable) {
|
||||||
return $request->isConduit();
|
return $request->isConduit();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handleRequestException(
|
public function handleRequestThrowable(
|
||||||
AphrontRequest $request,
|
AphrontRequest $request,
|
||||||
Exception $ex) {
|
$throwable) {
|
||||||
|
|
||||||
$response = id(new ConduitAPIResponse())
|
$response = id(new ConduitAPIResponse())
|
||||||
->setErrorCode(get_class($ex))
|
->setErrorCode(get_class($throwable))
|
||||||
->setErrorInfo($ex->getMessage());
|
->setErrorInfo($throwable->getMessage());
|
||||||
|
|
||||||
return id(new AphrontJSONResponse())
|
return id(new AphrontJSONResponse())
|
||||||
->setAddJSONShield(false)
|
->setAddJSONShield(false)
|
||||||
|
|
|
@ -11,9 +11,9 @@ final class PhabricatorDefaultRequestExceptionHandler
|
||||||
return pht('Handles all other exceptions.');
|
return pht('Handles all other exceptions.');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function canHandleRequestException(
|
public function canHandleRequestThrowable(
|
||||||
AphrontRequest $request,
|
AphrontRequest $request,
|
||||||
Exception $ex) {
|
$throwable) {
|
||||||
|
|
||||||
if (!$this->isPhabricatorSite($request)) {
|
if (!$this->isPhabricatorSite($request)) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -22,9 +22,9 @@ final class PhabricatorDefaultRequestExceptionHandler
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handleRequestException(
|
public function handleRequestThrowable(
|
||||||
AphrontRequest $request,
|
AphrontRequest $request,
|
||||||
Exception $ex) {
|
$throwable) {
|
||||||
|
|
||||||
$viewer = $this->getViewer($request);
|
$viewer = $this->getViewer($request);
|
||||||
|
|
||||||
|
@ -33,18 +33,18 @@ final class PhabricatorDefaultRequestExceptionHandler
|
||||||
// the internet. These include requests with bad CSRF tokens and
|
// the internet. These include requests with bad CSRF tokens and
|
||||||
// questionable "Host" headers.
|
// questionable "Host" headers.
|
||||||
$should_log = true;
|
$should_log = true;
|
||||||
if ($ex instanceof AphrontMalformedRequestException) {
|
if ($throwable instanceof AphrontMalformedRequestException) {
|
||||||
$should_log = !$ex->getIsUnlogged();
|
$should_log = !$throwable->getIsUnlogged();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($should_log) {
|
if ($should_log) {
|
||||||
phlog($ex);
|
phlog($throwable);
|
||||||
}
|
}
|
||||||
|
|
||||||
$class = get_class($ex);
|
$class = get_class($throwable);
|
||||||
$message = $ex->getMessage();
|
$message = $throwable->getMessage();
|
||||||
|
|
||||||
if ($ex instanceof AphrontSchemaQueryException) {
|
if ($throwable instanceof AphrontSchemaQueryException) {
|
||||||
$message .= "\n\n".pht(
|
$message .= "\n\n".pht(
|
||||||
"NOTE: This usually indicates that the MySQL schema has not been ".
|
"NOTE: This usually indicates that the MySQL schema has not been ".
|
||||||
"properly upgraded. Run '%s' to ensure your schema is up to date.",
|
"properly upgraded. Run '%s' to ensure your schema is up to date.",
|
||||||
|
@ -54,7 +54,7 @@ final class PhabricatorDefaultRequestExceptionHandler
|
||||||
if (PhabricatorEnv::getEnvConfig('phabricator.developer-mode')) {
|
if (PhabricatorEnv::getEnvConfig('phabricator.developer-mode')) {
|
||||||
$trace = id(new AphrontStackTraceView())
|
$trace = id(new AphrontStackTraceView())
|
||||||
->setUser($viewer)
|
->setUser($viewer)
|
||||||
->setTrace($ex->getTrace());
|
->setTrace($throwable->getTrace());
|
||||||
} else {
|
} else {
|
||||||
$trace = null;
|
$trace = null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,26 +13,26 @@ final class PhabricatorHighSecurityRequestExceptionHandler
|
||||||
'to present MFA credentials to take an action.');
|
'to present MFA credentials to take an action.');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function canHandleRequestException(
|
public function canHandleRequestThrowable(
|
||||||
AphrontRequest $request,
|
AphrontRequest $request,
|
||||||
Exception $ex) {
|
$throwable) {
|
||||||
|
|
||||||
if (!$this->isPhabricatorSite($request)) {
|
if (!$this->isPhabricatorSite($request)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ($ex instanceof PhabricatorAuthHighSecurityRequiredException);
|
return ($throwable instanceof PhabricatorAuthHighSecurityRequiredException);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handleRequestException(
|
public function handleRequestThrowable(
|
||||||
AphrontRequest $request,
|
AphrontRequest $request,
|
||||||
Exception $ex) {
|
$throwable) {
|
||||||
|
|
||||||
$viewer = $this->getViewer($request);
|
$viewer = $this->getViewer($request);
|
||||||
|
|
||||||
$form = id(new PhabricatorAuthSessionEngine())->renderHighSecurityForm(
|
$form = id(new PhabricatorAuthSessionEngine())->renderHighSecurityForm(
|
||||||
$ex->getFactors(),
|
$throwable->getFactors(),
|
||||||
$ex->getFactorValidationResults(),
|
$throwable->getFactorValidationResults(),
|
||||||
$viewer,
|
$viewer,
|
||||||
$request);
|
$request);
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ final class PhabricatorHighSecurityRequestExceptionHandler
|
||||||
'period of time. When you are finished taking sensitive '.
|
'period of time. When you are finished taking sensitive '.
|
||||||
'actions, you should leave high security.'))
|
'actions, you should leave high security.'))
|
||||||
->setSubmitURI($request->getPath())
|
->setSubmitURI($request->getPath())
|
||||||
->addCancelButton($ex->getCancelURI())
|
->addCancelButton($throwable->getCancelURI())
|
||||||
->addSubmitButton(pht('Enter High Security'));
|
->addSubmitButton(pht('Enter High Security'));
|
||||||
|
|
||||||
$request_parameters = $request->getPassthroughRequestParameters(
|
$request_parameters = $request->getPassthroughRequestParameters(
|
||||||
|
|
|
@ -13,20 +13,20 @@ final class PhabricatorPolicyRequestExceptionHandler
|
||||||
'do something they do not have permission to do.');
|
'do something they do not have permission to do.');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function canHandleRequestException(
|
public function canHandleRequestThrowable(
|
||||||
AphrontRequest $request,
|
AphrontRequest $request,
|
||||||
Exception $ex) {
|
$throwable) {
|
||||||
|
|
||||||
if (!$this->isPhabricatorSite($request)) {
|
if (!$this->isPhabricatorSite($request)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ($ex instanceof PhabricatorPolicyException);
|
return ($throwable instanceof PhabricatorPolicyException);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handleRequestException(
|
public function handleRequestThrowable(
|
||||||
AphrontRequest $request,
|
AphrontRequest $request,
|
||||||
Exception $ex) {
|
$throwable) {
|
||||||
|
|
||||||
$viewer = $this->getViewer($request);
|
$viewer = $this->getViewer($request);
|
||||||
|
|
||||||
|
@ -52,12 +52,12 @@ final class PhabricatorPolicyRequestExceptionHandler
|
||||||
array(
|
array(
|
||||||
'class' => 'aphront-policy-rejection',
|
'class' => 'aphront-policy-rejection',
|
||||||
),
|
),
|
||||||
$ex->getRejection()),
|
$throwable->getRejection()),
|
||||||
);
|
);
|
||||||
|
|
||||||
$list = null;
|
$list = null;
|
||||||
if ($ex->getCapabilityName()) {
|
if ($throwable->getCapabilityName()) {
|
||||||
$list = $ex->getMoreInfo();
|
$list = $throwable->getMoreInfo();
|
||||||
foreach ($list as $key => $item) {
|
foreach ($list as $key => $item) {
|
||||||
$list[$key] = $item;
|
$list[$key] = $item;
|
||||||
}
|
}
|
||||||
|
@ -67,12 +67,14 @@ final class PhabricatorPolicyRequestExceptionHandler
|
||||||
array(
|
array(
|
||||||
'class' => 'aphront-capability-details',
|
'class' => 'aphront-capability-details',
|
||||||
),
|
),
|
||||||
pht('Users with the "%s" capability:', $ex->getCapabilityName()));
|
pht(
|
||||||
|
'Users with the "%s" capability:',
|
||||||
|
$throwable->getCapabilityName()));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$dialog = id(new AphrontDialogView())
|
$dialog = id(new AphrontDialogView())
|
||||||
->setTitle($ex->getTitle())
|
->setTitle($throwable->getTitle())
|
||||||
->setClass('aphront-access-dialog')
|
->setClass('aphront-access-dialog')
|
||||||
->setUser($viewer)
|
->setUser($viewer)
|
||||||
->appendChild($content);
|
->appendChild($content);
|
||||||
|
|
|
@ -13,20 +13,20 @@ final class PhabricatorRateLimitRequestExceptionHandler
|
||||||
'does something too frequently.');
|
'does something too frequently.');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function canHandleRequestException(
|
public function canHandleRequestThrowable(
|
||||||
AphrontRequest $request,
|
AphrontRequest $request,
|
||||||
Exception $ex) {
|
$throwable) {
|
||||||
|
|
||||||
if (!$this->isPhabricatorSite($request)) {
|
if (!$this->isPhabricatorSite($request)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ($ex instanceof PhabricatorSystemActionRateLimitException);
|
return ($throwable instanceof PhabricatorSystemActionRateLimitException);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handleRequestException(
|
public function handleRequestThrowable(
|
||||||
AphrontRequest $request,
|
AphrontRequest $request,
|
||||||
Exception $ex) {
|
$throwable) {
|
||||||
|
|
||||||
$viewer = $this->getViewer($request);
|
$viewer = $this->getViewer($request);
|
||||||
|
|
||||||
|
@ -34,8 +34,8 @@ final class PhabricatorRateLimitRequestExceptionHandler
|
||||||
->setTitle(pht('Slow Down!'))
|
->setTitle(pht('Slow Down!'))
|
||||||
->setUser($viewer)
|
->setUser($viewer)
|
||||||
->setErrors(array(pht('You are being rate limited.')))
|
->setErrors(array(pht('You are being rate limited.')))
|
||||||
->appendParagraph($ex->getMessage())
|
->appendParagraph($throwable->getMessage())
|
||||||
->appendParagraph($ex->getRateExplanation())
|
->appendParagraph($throwable->getRateExplanation())
|
||||||
->addCancelButton('/', pht('Okaaaaaaaaaaaaaay...'));
|
->addCancelButton('/', pht('Okaaaaaaaaaaaaaay...'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -331,6 +331,14 @@ final class PhabricatorAuditInlineComment
|
||||||
return $this->isGhost;
|
return $this->isGhost;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getDateModified() {
|
||||||
|
return $this->proxy->getDateModified();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDateCreated() {
|
||||||
|
return $this->proxy->getDateCreated();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* -( PhabricatorMarkupInterface Implementation )-------------------------- */
|
/* -( PhabricatorMarkupInterface Implementation )-------------------------- */
|
||||||
|
|
||||||
|
|
|
@ -483,9 +483,11 @@ abstract class PhabricatorController extends AphrontController {
|
||||||
// NOTE: Applications (objects of class PhabricatorApplication) can't
|
// NOTE: Applications (objects of class PhabricatorApplication) can't
|
||||||
// currently be set here, although they don't need any of the extensions
|
// currently be set here, although they don't need any of the extensions
|
||||||
// anyway. This should probably work differently than it does, though.
|
// anyway. This should probably work differently than it does, though.
|
||||||
|
if ($object) {
|
||||||
if ($object instanceof PhabricatorLiskDAO) {
|
if ($object instanceof PhabricatorLiskDAO) {
|
||||||
$action_list->setObject($object);
|
$action_list->setObject($object);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$curtain = id(new PHUICurtainView())
|
$curtain = id(new PHUICurtainView())
|
||||||
->setViewer($viewer)
|
->setViewer($viewer)
|
||||||
|
|
|
@ -6,119 +6,79 @@ final class PhabricatorCacheManagementPurgeWorkflow
|
||||||
protected function didConstruct() {
|
protected function didConstruct() {
|
||||||
$this
|
$this
|
||||||
->setName('purge')
|
->setName('purge')
|
||||||
->setSynopsis(pht('Drop data from caches. APC-based caches can be '.
|
->setSynopsis(pht('Drop data from readthrough caches.'))
|
||||||
'purged from the web interface.'))
|
|
||||||
->setArguments(
|
->setArguments(
|
||||||
array(
|
array(
|
||||||
array(
|
array(
|
||||||
'name' => 'purge-all',
|
'name' => 'all',
|
||||||
'help' => pht('Purge all caches.'),
|
'help' => pht('Purge all caches.'),
|
||||||
),
|
),
|
||||||
array(
|
array(
|
||||||
'name' => 'purge-remarkup',
|
'name' => 'caches',
|
||||||
'help' => pht('Purge the remarkup cache.'),
|
'param' => 'keys',
|
||||||
),
|
'help' => pht('Purge a specific set of caches.'),
|
||||||
array(
|
|
||||||
'name' => 'purge-changeset',
|
|
||||||
'help' => pht('Purge the Differential changeset cache.'),
|
|
||||||
),
|
|
||||||
array(
|
|
||||||
'name' => 'purge-general',
|
|
||||||
'help' => pht('Purge the general cache.'),
|
|
||||||
),
|
|
||||||
array(
|
|
||||||
'name' => 'purge-user',
|
|
||||||
'help' => pht('Purge the user cache.'),
|
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function execute(PhutilArgumentParser $args) {
|
public function execute(PhutilArgumentParser $args) {
|
||||||
$console = PhutilConsole::getConsole();
|
$all_purgers = PhabricatorCachePurger::getAllPurgers();
|
||||||
|
|
||||||
$purge_all = $args->getArg('purge-all');
|
$is_all = $args->getArg('all');
|
||||||
|
$key_list = $args->getArg('caches');
|
||||||
$purge = array(
|
|
||||||
'remarkup' => $purge_all || $args->getArg('purge-remarkup'),
|
|
||||||
'changeset' => $purge_all || $args->getArg('purge-changeset'),
|
|
||||||
'general' => $purge_all || $args->getArg('purge-general'),
|
|
||||||
'user' => $purge_all || $args->getArg('purge-user'),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!array_filter($purge)) {
|
|
||||||
$list = array();
|
|
||||||
foreach ($purge as $key => $ignored) {
|
|
||||||
$list[] = "'--purge-".$key."'";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if ($is_all && strlen($key_list)) {
|
||||||
throw new PhutilArgumentUsageException(
|
throw new PhutilArgumentUsageException(
|
||||||
pht(
|
pht(
|
||||||
"Specify which cache or caches to purge, or use '%s'. Available ".
|
'Specify either "--all" or "--caches", not both.'));
|
||||||
"caches are: %s. Use '%s' for more information.",
|
} else if (!$is_all && !strlen($key_list)) {
|
||||||
'--purge-all',
|
throw new PhutilArgumentUsageException(
|
||||||
implode(', ', $list),
|
pht(
|
||||||
'--help'));
|
'Select caches to purge with "--all" or "--caches". Available '.
|
||||||
|
'caches are: %s.',
|
||||||
|
implode(', ', array_keys($all_purgers))));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($purge['remarkup']) {
|
if ($is_all) {
|
||||||
$console->writeOut(pht('Purging remarkup cache...'));
|
$purgers = $all_purgers;
|
||||||
$this->purgeRemarkupCache();
|
} else {
|
||||||
$console->writeOut("%s\n", pht('Done.'));
|
$key_list = preg_split('/[\s,]+/', $key_list);
|
||||||
|
$purgers = array();
|
||||||
|
foreach ($key_list as $key) {
|
||||||
|
if (isset($all_purgers[$key])) {
|
||||||
|
$purgers[$key] = $all_purgers[$key];
|
||||||
|
} else {
|
||||||
|
throw new PhutilArgumentUsageException(
|
||||||
|
pht(
|
||||||
|
'Cache purger "%s" is not recognized. Available caches '.
|
||||||
|
'are: %s.',
|
||||||
|
$key,
|
||||||
|
implode(', ', array_keys($all_purgers))));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($purge['changeset']) {
|
|
||||||
$console->writeOut(pht('Purging changeset cache...'));
|
|
||||||
$this->purgeChangesetCache();
|
|
||||||
$console->writeOut("%s\n", pht('Done.'));
|
|
||||||
}
|
}
|
||||||
|
if (!$purgers) {
|
||||||
if ($purge['general']) {
|
throw new PhutilArgumentUsageException(
|
||||||
$console->writeOut(pht('Purging general cache...'));
|
pht(
|
||||||
$this->purgeGeneralCache();
|
'When using "--caches", you must select at least one valid '.
|
||||||
$console->writeOut("%s\n", pht('Done.'));
|
'cache to purge.'));
|
||||||
}
|
|
||||||
|
|
||||||
if ($purge['user']) {
|
|
||||||
$console->writeOut(pht('Purging user cache...'));
|
|
||||||
$this->purgeUserCache();
|
|
||||||
$console->writeOut("%s\n", pht('Done.'));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function purgeRemarkupCache() {
|
$viewer = $this->getViewer();
|
||||||
$conn_w = id(new PhabricatorMarkupCache())->establishConnection('w');
|
|
||||||
|
|
||||||
queryfx(
|
foreach ($purgers as $key => $purger) {
|
||||||
$conn_w,
|
$purger->setViewer($viewer);
|
||||||
'TRUNCATE TABLE %T',
|
|
||||||
id(new PhabricatorMarkupCache())->getTableName());
|
echo tsprintf(
|
||||||
|
"%s\n",
|
||||||
|
pht(
|
||||||
|
'Purging "%s" cache...',
|
||||||
|
$key));
|
||||||
|
|
||||||
|
$purger->purgeCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
private function purgeChangesetCache() {
|
return 0;
|
||||||
$conn_w = id(new DifferentialChangeset())->establishConnection('w');
|
|
||||||
queryfx(
|
|
||||||
$conn_w,
|
|
||||||
'TRUNCATE TABLE %T',
|
|
||||||
DifferentialChangeset::TABLE_CACHE);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function purgeGeneralCache() {
|
|
||||||
$conn_w = id(new PhabricatorMarkupCache())->establishConnection('w');
|
|
||||||
|
|
||||||
queryfx(
|
|
||||||
$conn_w,
|
|
||||||
'TRUNCATE TABLE %T',
|
|
||||||
'cache_general');
|
|
||||||
}
|
|
||||||
|
|
||||||
private function purgeUserCache() {
|
|
||||||
$table = new PhabricatorUserCache();
|
|
||||||
$conn_w = $table->establishConnection('w');
|
|
||||||
|
|
||||||
queryfx(
|
|
||||||
$conn_w,
|
|
||||||
'TRUNCATE TABLE %T',
|
|
||||||
$table->getTableName());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
22
src/applications/cache/purger/PhabricatorBuiltinFileCachePurger.php
vendored
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorBuiltinFileCachePurger
|
||||||
|
extends PhabricatorCachePurger {
|
||||||
|
|
||||||
|
const PURGERKEY = 'builtin-file';
|
||||||
|
|
||||||
|
public function purgeCache() {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
$files = id(new PhabricatorFileQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withIsBuiltin(true)
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
$engine = new PhabricatorDestructionEngine();
|
||||||
|
foreach ($files as $file) {
|
||||||
|
$engine->destroyObject($file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
30
src/applications/cache/purger/PhabricatorCachePurger.php
vendored
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
abstract class PhabricatorCachePurger
|
||||||
|
extends Phobject {
|
||||||
|
|
||||||
|
private $viewer;
|
||||||
|
|
||||||
|
abstract public function purgeCache();
|
||||||
|
|
||||||
|
final public function setViewer(PhabricatorUser $viewer) {
|
||||||
|
$this->viewer = $viewer;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
final public function getViewer() {
|
||||||
|
return $this->viewer;
|
||||||
|
}
|
||||||
|
|
||||||
|
final public function getPurgerKey() {
|
||||||
|
return $this->getPhobjectClassConstant('PURGERKEY');
|
||||||
|
}
|
||||||
|
|
||||||
|
final public static function getAllPurgers() {
|
||||||
|
return id(new PhutilClassMapQuery())
|
||||||
|
->setAncestorClass(__CLASS__)
|
||||||
|
->setUniqueMethod('getPurgerKey')
|
||||||
|
->execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
18
src/applications/cache/purger/PhabricatorChangesetCachePurger.php
vendored
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorChangesetCachePurger
|
||||||
|
extends PhabricatorCachePurger {
|
||||||
|
|
||||||
|
const PURGERKEY = 'changeset';
|
||||||
|
|
||||||
|
public function purgeCache() {
|
||||||
|
$table = new DifferentialChangeset();
|
||||||
|
$conn = $table->establishConnection('w');
|
||||||
|
|
||||||
|
queryfx(
|
||||||
|
$conn,
|
||||||
|
'TRUNCATE TABLE %T',
|
||||||
|
DifferentialChangeset::TABLE_CACHE);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
18
src/applications/cache/purger/PhabricatorGeneralCachePurger.php
vendored
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorGeneralCachePurger
|
||||||
|
extends PhabricatorCachePurger {
|
||||||
|
|
||||||
|
const PURGERKEY = 'general';
|
||||||
|
|
||||||
|
public function purgeCache() {
|
||||||
|
$table = new PhabricatorMarkupCache();
|
||||||
|
$conn = $table->establishConnection('w');
|
||||||
|
|
||||||
|
queryfx(
|
||||||
|
$conn,
|
||||||
|
'TRUNCATE TABLE %T',
|
||||||
|
'cache_general');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
18
src/applications/cache/purger/PhabricatorRemarkupCachePurger.php
vendored
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorRemarkupCachePurger
|
||||||
|
extends PhabricatorCachePurger {
|
||||||
|
|
||||||
|
const PURGERKEY = 'remarkup';
|
||||||
|
|
||||||
|
public function purgeCache() {
|
||||||
|
$table = new PhabricatorMarkupCache();
|
||||||
|
$conn = $table->establishConnection('w');
|
||||||
|
|
||||||
|
queryfx(
|
||||||
|
$conn,
|
||||||
|
'TRUNCATE TABLE %T',
|
||||||
|
$table->getTableName());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
18
src/applications/cache/purger/PhabricatorUserCachePurger.php
vendored
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorUserCachePurger
|
||||||
|
extends PhabricatorCachePurger {
|
||||||
|
|
||||||
|
const PURGERKEY = 'user';
|
||||||
|
|
||||||
|
public function purgeCache() {
|
||||||
|
$table = new PhabricatorUserCache();
|
||||||
|
$conn = $table->establishConnection('w');
|
||||||
|
|
||||||
|
queryfx(
|
||||||
|
$conn,
|
||||||
|
'TRUNCATE TABLE %T',
|
||||||
|
$table->getTableName());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -49,6 +49,13 @@ final class PhabricatorCalendarEventHeraldAdapter extends HeraldAdapter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getRepetitionOptions() {
|
||||||
|
return array(
|
||||||
|
HeraldRepetitionPolicyConfig::EVERY,
|
||||||
|
HeraldRepetitionPolicyConfig::FIRST,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public function getHeraldName() {
|
public function getHeraldName() {
|
||||||
return $this->getObject()->getMonogram();
|
return $this->getObject()->getMonogram();
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,8 +42,7 @@ final class PhabricatorDashboardPanelDatasource
|
||||||
$properties = $panel->getProperties();
|
$properties = $panel->getProperties();
|
||||||
|
|
||||||
$result = id(new PhabricatorTypeaheadResult())
|
$result = id(new PhabricatorTypeaheadResult())
|
||||||
->setName($panel->getName())
|
->setName($monogram.' '.$panel->getName())
|
||||||
->setDisplayName($monogram.' '.$panel->getName())
|
|
||||||
->setPHID($id)
|
->setPHID($id)
|
||||||
->setIcon($impl->getIcon())
|
->setIcon($impl->getIcon())
|
||||||
->addAttribute($type_text);
|
->addAttribute($type_text);
|
||||||
|
|
|
@ -41,12 +41,6 @@ final class PhabricatorDifferentialApplication extends PhabricatorApplication {
|
||||||
return "\xE2\x9A\x99";
|
return "\xE2\x9A\x99";
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getEventListeners() {
|
|
||||||
return array(
|
|
||||||
new DifferentialLandingActionMenuEventListener(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getOverview() {
|
public function getOverview() {
|
||||||
return pht(
|
return pht(
|
||||||
'Differential is a **code review application** which allows '.
|
'Differential is a **code review application** which allows '.
|
||||||
|
@ -69,14 +63,14 @@ final class PhabricatorDifferentialApplication extends PhabricatorApplication {
|
||||||
=> 'DifferentialRevisionEditController',
|
=> 'DifferentialRevisionEditController',
|
||||||
$this->getEditRoutePattern('attach/(?P<diffID>[^/]+)/to/')
|
$this->getEditRoutePattern('attach/(?P<diffID>[^/]+)/to/')
|
||||||
=> 'DifferentialRevisionEditController',
|
=> 'DifferentialRevisionEditController',
|
||||||
'land/(?:(?P<id>[1-9]\d*))/(?P<strategy>[^/]+)/'
|
|
||||||
=> 'DifferentialRevisionLandController',
|
|
||||||
'closedetails/(?P<phid>[^/]+)/'
|
'closedetails/(?P<phid>[^/]+)/'
|
||||||
=> 'DifferentialRevisionCloseDetailsController',
|
=> 'DifferentialRevisionCloseDetailsController',
|
||||||
'update/(?P<revisionID>[1-9]\d*)/'
|
'update/(?P<revisionID>[1-9]\d*)/'
|
||||||
=> 'DifferentialDiffCreateController',
|
=> 'DifferentialDiffCreateController',
|
||||||
'operation/(?P<id>[1-9]\d*)/'
|
'operation/(?P<id>[1-9]\d*)/'
|
||||||
=> 'DifferentialRevisionOperationController',
|
=> 'DifferentialRevisionOperationController',
|
||||||
|
'inlines/(?P<id>[1-9]\d*)/'
|
||||||
|
=> 'DifferentialRevisionInlinesController',
|
||||||
),
|
),
|
||||||
'comment/' => array(
|
'comment/' => array(
|
||||||
'preview/(?P<id>[1-9]\d*)/' => 'DifferentialCommentPreviewController',
|
'preview/(?P<id>[1-9]\d*)/' => 'DifferentialCommentPreviewController',
|
||||||
|
|
|
@ -0,0 +1,190 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class DifferentialRevisionInlinesController
|
||||||
|
extends DifferentialController {
|
||||||
|
|
||||||
|
public function shouldAllowPublic() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handleRequest(AphrontRequest $request) {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
$id = $request->getURIData('id');
|
||||||
|
|
||||||
|
$revision = id(new DifferentialRevisionQuery())
|
||||||
|
->withIDs(array($id))
|
||||||
|
->setViewer($viewer)
|
||||||
|
->needDiffIDs(true)
|
||||||
|
->executeOne();
|
||||||
|
if (!$revision) {
|
||||||
|
return new Aphront404Response();
|
||||||
|
}
|
||||||
|
|
||||||
|
$revision_monogram = $revision->getMonogram();
|
||||||
|
$revision_uri = $revision->getURI();
|
||||||
|
$revision_title = $revision->getTitle();
|
||||||
|
|
||||||
|
$query = id(new DifferentialInlineCommentQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->needHidden(true)
|
||||||
|
->withRevisionPHIDs(array($revision->getPHID()));
|
||||||
|
$inlines = $query->execute();
|
||||||
|
|
||||||
|
$crumbs = $this->buildApplicationCrumbs();
|
||||||
|
$crumbs->addTextCrumb($revision_monogram, $revision_uri);
|
||||||
|
$crumbs->addTextCrumb(pht('Inline Comments'));
|
||||||
|
$crumbs->setBorder(true);
|
||||||
|
|
||||||
|
$content = $this->renderInlineTable($revision, $inlines);
|
||||||
|
$header = $this->buildHeader($revision);
|
||||||
|
|
||||||
|
$view = id(new PHUITwoColumnView())
|
||||||
|
->setHeader($header)
|
||||||
|
->setFooter($content);
|
||||||
|
|
||||||
|
return $this->newPage()
|
||||||
|
->setTitle(
|
||||||
|
array(
|
||||||
|
"{$revision_monogram} {$revision_title}",
|
||||||
|
pht('Inlines'),
|
||||||
|
))
|
||||||
|
->setCrumbs($crumbs)
|
||||||
|
->appendChild($view);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function buildHeader(DifferentialRevision $revision) {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
$button = id(new PHUIButtonView())
|
||||||
|
->setTag('a')
|
||||||
|
->setIcon('fa-chevron-left')
|
||||||
|
->setHref($revision->getURI())
|
||||||
|
->setText(pht('Back to Revision'));
|
||||||
|
|
||||||
|
return id(new PHUIHeaderView())
|
||||||
|
->setHeader($revision->getTitle())
|
||||||
|
->setUser($viewer)
|
||||||
|
->setHeaderIcon('fa-cog')
|
||||||
|
->addActionLink($button);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function renderInlineTable(
|
||||||
|
DifferentialRevision $revision,
|
||||||
|
array $inlines) {
|
||||||
|
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
$inlines = id(new PHUIDiffInlineThreader())
|
||||||
|
->reorderAndThreadCommments($inlines);
|
||||||
|
|
||||||
|
$handle_phids = array();
|
||||||
|
$changeset_ids = array();
|
||||||
|
foreach ($inlines as $inline) {
|
||||||
|
$handle_phids[] = $inline->getAuthorPHID();
|
||||||
|
$changeset_ids[] = $inline->getChangesetID();
|
||||||
|
}
|
||||||
|
$handles = $viewer->loadHandles($handle_phids);
|
||||||
|
$handles = iterator_to_array($handles);
|
||||||
|
|
||||||
|
if ($changeset_ids) {
|
||||||
|
$changesets = id(new DifferentialChangesetQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withIDs($changeset_ids)
|
||||||
|
->execute();
|
||||||
|
$changesets = mpull($changesets, null, 'getID');
|
||||||
|
} else {
|
||||||
|
$changesets = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
$current_changeset = head($revision->getDiffIDs());
|
||||||
|
|
||||||
|
$rows = array();
|
||||||
|
foreach ($inlines as $inline) {
|
||||||
|
$status_icons = array();
|
||||||
|
|
||||||
|
$c_id = $inline->getChangesetID();
|
||||||
|
$d_id = $changesets[$c_id]->getDiffID();
|
||||||
|
|
||||||
|
if ($d_id == $current_changeset) {
|
||||||
|
$diff_id = phutil_tag('strong', array(), pht('Current'));
|
||||||
|
} else {
|
||||||
|
$diff_id = pht('Diff %d', $d_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
$reviewer = $handles[$inline->getAuthorPHID()]->renderLink();
|
||||||
|
$now = PhabricatorTime::getNow();
|
||||||
|
$then = $inline->getDateModified();
|
||||||
|
$datetime = phutil_format_relative_time($now - $then);
|
||||||
|
|
||||||
|
$comment_href = $revision->getURI().'#inline-'.$inline->getID();
|
||||||
|
$comment = phutil_tag(
|
||||||
|
'a',
|
||||||
|
array(
|
||||||
|
'href' => $comment_href,
|
||||||
|
),
|
||||||
|
$inline->getContent());
|
||||||
|
|
||||||
|
$state = $inline->getFixedState();
|
||||||
|
if ($state == PhabricatorInlineCommentInterface::STATE_DONE) {
|
||||||
|
$status_icons[] = id(new PHUIIconView())
|
||||||
|
->setIcon('fa-check green')
|
||||||
|
->addClass('mmr');
|
||||||
|
} else if ($inline->getReplyToCommentPHID() &&
|
||||||
|
$inline->getAuthorPHID() == $revision->getAuthorPHID()) {
|
||||||
|
$status_icons[] = id(new PHUIIconView())
|
||||||
|
->setIcon('fa-commenting-o blue')
|
||||||
|
->addClass('mmr');
|
||||||
|
} else {
|
||||||
|
$status_icons[] = id(new PHUIIconView())
|
||||||
|
->setIcon('fa-circle-o grey')
|
||||||
|
->addClass('mmr');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if ($inline->getReplyToCommentPHID()) {
|
||||||
|
$reply_icon = id(new PHUIIconView())
|
||||||
|
->setIcon('fa-reply mmr darkgrey');
|
||||||
|
$comment = array($reply_icon, $comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
$rows[] = array(
|
||||||
|
$diff_id,
|
||||||
|
$status_icons,
|
||||||
|
$reviewer,
|
||||||
|
AphrontTableView::renderSingleDisplayLine($comment),
|
||||||
|
$datetime,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$table = new AphrontTableView($rows);
|
||||||
|
$table->setHeaders(
|
||||||
|
array(
|
||||||
|
pht('Diff'),
|
||||||
|
pht('Status'),
|
||||||
|
pht('Reviewer'),
|
||||||
|
pht('Comment'),
|
||||||
|
pht('Created'),
|
||||||
|
));
|
||||||
|
$table->setColumnClasses(
|
||||||
|
array(
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
'wide',
|
||||||
|
'right',
|
||||||
|
));
|
||||||
|
$table->setColumnVisibility(
|
||||||
|
array(
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
));
|
||||||
|
|
||||||
|
return id(new PHUIObjectBoxView())
|
||||||
|
->setHeaderText(pht('Inline Comments'))
|
||||||
|
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
||||||
|
->setTable($table);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,157 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
final class DifferentialRevisionLandController extends DifferentialController {
|
|
||||||
|
|
||||||
private $pushStrategy;
|
|
||||||
|
|
||||||
public function handleRequest(AphrontRequest $request) {
|
|
||||||
$viewer = $this->getViewer();
|
|
||||||
$revision_id = $request->getURIData('id');
|
|
||||||
$strategy_class = $request->getURIData('strategy');
|
|
||||||
|
|
||||||
$revision = id(new DifferentialRevisionQuery())
|
|
||||||
->withIDs(array($revision_id))
|
|
||||||
->setViewer($viewer)
|
|
||||||
->executeOne();
|
|
||||||
if (!$revision) {
|
|
||||||
return new Aphront404Response();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_subclass_of($strategy_class, 'DifferentialLandingStrategy')) {
|
|
||||||
$this->pushStrategy = newv($strategy_class, array());
|
|
||||||
} else {
|
|
||||||
throw new Exception(
|
|
||||||
pht(
|
|
||||||
"Strategy type must be a valid class name and must subclass ".
|
|
||||||
"%s. '%s' is not a subclass of %s",
|
|
||||||
'DifferentialLandingStrategy',
|
|
||||||
$strategy_class,
|
|
||||||
'DifferentialLandingStrategy'));
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($request->isDialogFormPost()) {
|
|
||||||
$response = null;
|
|
||||||
$text = '';
|
|
||||||
try {
|
|
||||||
$response = $this->attemptLand($revision, $request);
|
|
||||||
$title = pht('Success!');
|
|
||||||
$text = pht('Revision was successfully landed.');
|
|
||||||
} catch (Exception $ex) {
|
|
||||||
$title = pht('Failed to land revision');
|
|
||||||
if ($ex instanceof PhutilProxyException) {
|
|
||||||
$text = hsprintf(
|
|
||||||
'%s:<br><pre>%s</pre>',
|
|
||||||
$ex->getMessage(),
|
|
||||||
$ex->getPreviousException()->getMessage());
|
|
||||||
} else {
|
|
||||||
$text = phutil_tag('pre', array(), $ex->getMessage());
|
|
||||||
}
|
|
||||||
$text = id(new PHUIInfoView())
|
|
||||||
->appendChild($text);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($response instanceof AphrontDialogView) {
|
|
||||||
$dialog = $response;
|
|
||||||
} else {
|
|
||||||
$dialog = id(new AphrontDialogView())
|
|
||||||
->setUser($viewer)
|
|
||||||
->setTitle($title)
|
|
||||||
->appendChild(phutil_tag('p', array(), $text))
|
|
||||||
->addCancelButton('/D'.$revision_id, pht('Done'));
|
|
||||||
}
|
|
||||||
return id(new AphrontDialogResponse())->setDialog($dialog);
|
|
||||||
}
|
|
||||||
|
|
||||||
$is_disabled = $this->pushStrategy->isActionDisabled(
|
|
||||||
$viewer,
|
|
||||||
$revision,
|
|
||||||
$revision->getRepository());
|
|
||||||
if ($is_disabled) {
|
|
||||||
if (is_string($is_disabled)) {
|
|
||||||
$explain = $is_disabled;
|
|
||||||
} else {
|
|
||||||
$explain = pht('This action is not currently enabled.');
|
|
||||||
}
|
|
||||||
$dialog = id(new AphrontDialogView())
|
|
||||||
->setUser($viewer)
|
|
||||||
->setTitle(pht("Can't land revision"))
|
|
||||||
->appendChild($explain)
|
|
||||||
->addCancelButton('/D'.$revision_id);
|
|
||||||
|
|
||||||
return id(new AphrontDialogResponse())->setDialog($dialog);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
$prompt = hsprintf('%s<br><br>%s',
|
|
||||||
pht(
|
|
||||||
'This will squash and rebase revision %s, and push it to '.
|
|
||||||
'the default / master branch.',
|
|
||||||
$revision_id),
|
|
||||||
pht('It is an experimental feature and may not work.'));
|
|
||||||
|
|
||||||
$dialog = id(new AphrontDialogView())
|
|
||||||
->setUser($viewer)
|
|
||||||
->setTitle(pht('Land Revision %s?', $revision_id))
|
|
||||||
->appendChild($prompt)
|
|
||||||
->setSubmitURI($request->getRequestURI())
|
|
||||||
->addSubmitButton(pht('Land it!'))
|
|
||||||
->addCancelButton('/D'.$revision_id);
|
|
||||||
|
|
||||||
return id(new AphrontDialogResponse())->setDialog($dialog);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function attemptLand($revision, $request) {
|
|
||||||
$status = $revision->getStatus();
|
|
||||||
if ($status != ArcanistDifferentialRevisionStatus::ACCEPTED) {
|
|
||||||
throw new Exception(pht('Only Accepted revisions can be landed.'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$repository = $revision->getRepository();
|
|
||||||
|
|
||||||
if ($repository === null) {
|
|
||||||
throw new Exception(pht('Revision is not attached to a repository.'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$can_push = PhabricatorPolicyFilter::hasCapability(
|
|
||||||
$request->getUser(),
|
|
||||||
$repository,
|
|
||||||
DiffusionPushCapability::CAPABILITY);
|
|
||||||
|
|
||||||
if (!$can_push) {
|
|
||||||
throw new Exception(
|
|
||||||
pht('You do not have permission to push to this repository.'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$lock = $this->lockRepository($repository);
|
|
||||||
|
|
||||||
try {
|
|
||||||
$response = $this->pushStrategy->processLandRequest(
|
|
||||||
$request,
|
|
||||||
$revision,
|
|
||||||
$repository);
|
|
||||||
} catch (Exception $e) {
|
|
||||||
$lock->unlock();
|
|
||||||
throw $e;
|
|
||||||
}
|
|
||||||
|
|
||||||
$lock->unlock();
|
|
||||||
|
|
||||||
$looksoon = new ConduitCall(
|
|
||||||
'diffusion.looksoon',
|
|
||||||
array(
|
|
||||||
'repositories' => array($repository->getPHID()),
|
|
||||||
));
|
|
||||||
$looksoon->setUser($request->getUser());
|
|
||||||
$looksoon->execute();
|
|
||||||
|
|
||||||
return $response;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function lockRepository($repository) {
|
|
||||||
$lock_name = __CLASS__.':'.($repository->getPHID());
|
|
||||||
$lock = PhabricatorGlobalLock::newLock($lock_name);
|
|
||||||
$lock->lock();
|
|
||||||
return $lock;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -281,6 +281,12 @@ final class DifferentialRevisionViewController extends DifferentialController {
|
||||||
->setTitle(pht('Diff %s', $target->getID()))
|
->setTitle(pht('Diff %s', $target->getID()))
|
||||||
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY);
|
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY);
|
||||||
|
|
||||||
|
|
||||||
|
$revision_id = $revision->getID();
|
||||||
|
$inline_list_uri = "/revision/inlines/{$revision_id}/";
|
||||||
|
$inline_list_uri = $this->getApplicationURI($inline_list_uri);
|
||||||
|
$changeset_view->setInlineListURI($inline_list_uri);
|
||||||
|
|
||||||
if ($repository) {
|
if ($repository) {
|
||||||
$changeset_view->setRepository($repository);
|
$changeset_view->setRepository($repository);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,186 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
final class DifferentialGitHubLandingStrategy
|
|
||||||
extends DifferentialLandingStrategy {
|
|
||||||
|
|
||||||
private $account;
|
|
||||||
private $provider;
|
|
||||||
|
|
||||||
public function processLandRequest(
|
|
||||||
AphrontRequest $request,
|
|
||||||
DifferentialRevision $revision,
|
|
||||||
PhabricatorRepository $repository) {
|
|
||||||
|
|
||||||
$viewer = $request->getUser();
|
|
||||||
$this->init($viewer, $repository);
|
|
||||||
|
|
||||||
$workspace = $this->getGitWorkspace($repository);
|
|
||||||
|
|
||||||
try {
|
|
||||||
id(new DifferentialHostedGitLandingStrategy())
|
|
||||||
->commitRevisionToWorkspace($revision, $workspace, $viewer);
|
|
||||||
} catch (Exception $e) {
|
|
||||||
throw new PhutilProxyException(pht('Failed to commit patch.'), $e);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
$this->pushWorkspaceRepository($repository, $workspace);
|
|
||||||
} catch (Exception $e) {
|
|
||||||
// If it's a permission problem, we know more than git.
|
|
||||||
$dialog = $this->verifyRemotePermissions($viewer, $revision, $repository);
|
|
||||||
if ($dialog) {
|
|
||||||
return $dialog;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Else, throw what git said.
|
|
||||||
throw new PhutilProxyException(
|
|
||||||
pht('Failed to push changes upstream.'),
|
|
||||||
$e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns PhabricatorActionView or an array of PhabricatorActionView or null.
|
|
||||||
*/
|
|
||||||
public function createMenuItem(
|
|
||||||
PhabricatorUser $viewer,
|
|
||||||
DifferentialRevision $revision,
|
|
||||||
PhabricatorRepository $repository) {
|
|
||||||
|
|
||||||
// TODO: This temporarily disables this action, because it doesn't work
|
|
||||||
// and is confusing to users. If you want to use it, comment out this line
|
|
||||||
// for now and we'll provide real support eventually.
|
|
||||||
return;
|
|
||||||
|
|
||||||
$vcs = $repository->getVersionControlSystem();
|
|
||||||
if ($vcs !== PhabricatorRepositoryType::REPOSITORY_TYPE_GIT) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($repository->isHosted()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
// These throw when failing.
|
|
||||||
$this->init($viewer, $repository);
|
|
||||||
$this->findGitHubRepo($repository);
|
|
||||||
} catch (Exception $e) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->createActionView($revision, pht('Land to GitHub'))
|
|
||||||
->setIcon('fa-cloud-upload');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function pushWorkspaceRepository(
|
|
||||||
PhabricatorRepository $repository,
|
|
||||||
ArcanistRepositoryAPI $workspace) {
|
|
||||||
|
|
||||||
$token = $this->getAccessToken();
|
|
||||||
|
|
||||||
$github_repo = $this->findGitHubRepo($repository);
|
|
||||||
|
|
||||||
$remote = urisprintf(
|
|
||||||
'https://%s:x-oauth-basic@%s/%s.git',
|
|
||||||
$token,
|
|
||||||
$this->provider->getProviderDomain(),
|
|
||||||
$github_repo);
|
|
||||||
|
|
||||||
$workspace->execxLocal(
|
|
||||||
'push %P HEAD:master',
|
|
||||||
new PhutilOpaqueEnvelope($remote));
|
|
||||||
}
|
|
||||||
|
|
||||||
private function init($viewer, $repository) {
|
|
||||||
$repo_uri = $repository->getRemoteURIObject();
|
|
||||||
$repo_domain = $repo_uri->getDomain();
|
|
||||||
|
|
||||||
$this->account = id(new PhabricatorExternalAccountQuery())
|
|
||||||
->setViewer($viewer)
|
|
||||||
->withUserPHIDs(array($viewer->getPHID()))
|
|
||||||
->withAccountTypes(array('github'))
|
|
||||||
->withAccountDomains(array($repo_domain))
|
|
||||||
->requireCapabilities(
|
|
||||||
array(
|
|
||||||
PhabricatorPolicyCapability::CAN_VIEW,
|
|
||||||
PhabricatorPolicyCapability::CAN_EDIT,
|
|
||||||
))
|
|
||||||
->executeOne();
|
|
||||||
|
|
||||||
if (!$this->account) {
|
|
||||||
throw new Exception(
|
|
||||||
pht('No matching GitHub account found for %s.', $repo_domain));
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->provider = PhabricatorAuthProvider::getEnabledProviderByKey(
|
|
||||||
$this->account->getProviderKey());
|
|
||||||
if (!$this->provider) {
|
|
||||||
throw new Exception(
|
|
||||||
pht('GitHub provider for %s is not enabled.', $repo_domain));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function findGitHubRepo(PhabricatorRepository $repository) {
|
|
||||||
$repo_uri = $repository->getRemoteURIObject();
|
|
||||||
|
|
||||||
$repo_path = $repo_uri->getPath();
|
|
||||||
|
|
||||||
if (substr($repo_path, -4) == '.git') {
|
|
||||||
$repo_path = substr($repo_path, 0, -4);
|
|
||||||
}
|
|
||||||
$repo_path = ltrim($repo_path, '/');
|
|
||||||
|
|
||||||
return $repo_path;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function getAccessToken() {
|
|
||||||
return $this->provider->getOAuthAccessToken($this->account);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function verifyRemotePermissions($viewer, $revision, $repository) {
|
|
||||||
$github_user = $this->account->getUsername();
|
|
||||||
$github_repo = $this->findGitHubRepo($repository);
|
|
||||||
|
|
||||||
$uri = urisprintf(
|
|
||||||
'https://api.github.com/repos/%s/collaborators/%s',
|
|
||||||
$github_repo,
|
|
||||||
$github_user);
|
|
||||||
|
|
||||||
$uri = new PhutilURI($uri);
|
|
||||||
$uri->setQueryParam('access_token', $this->getAccessToken());
|
|
||||||
list($status, $body, $headers) = id(new HTTPSFuture($uri))->resolve();
|
|
||||||
|
|
||||||
// Likely status codes:
|
|
||||||
// 204 No Content: Has permissions. Token might be too weak.
|
|
||||||
// 404 Not Found: Not a collaborator.
|
|
||||||
// 401 Unauthorized: Token is bad/revoked.
|
|
||||||
|
|
||||||
$no_permission = ($status->getStatusCode() == 404);
|
|
||||||
|
|
||||||
if ($no_permission) {
|
|
||||||
throw new Exception(
|
|
||||||
pht(
|
|
||||||
"You don't have permission to push to this repository. ".
|
|
||||||
"Push permissions for this repository are managed on GitHub."));
|
|
||||||
}
|
|
||||||
|
|
||||||
$scopes = BaseHTTPFuture::getHeader($headers, 'X-OAuth-Scopes');
|
|
||||||
if (strpos($scopes, 'public_repo') === false) {
|
|
||||||
$provider_key = $this->provider->getProviderKey();
|
|
||||||
$refresh_token_uri = new PhutilURI("/auth/refresh/{$provider_key}/");
|
|
||||||
$refresh_token_uri->setQueryParam('scope', 'public_repo');
|
|
||||||
|
|
||||||
return id(new AphrontDialogView())
|
|
||||||
->setUser($viewer)
|
|
||||||
->setTitle(pht('Stronger token needed'))
|
|
||||||
->appendChild(pht(
|
|
||||||
'In order to complete this action, you need a '.
|
|
||||||
'stronger GitHub token.'))
|
|
||||||
->setSubmitURI($refresh_token_uri)
|
|
||||||
->addCancelButton('/D'.$revision->getId())
|
|
||||||
->setDisableWorkflowOnSubmit(true)
|
|
||||||
->addSubmitButton(pht('Refresh Account Link'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,127 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
final class DifferentialHostedGitLandingStrategy
|
|
||||||
extends DifferentialLandingStrategy {
|
|
||||||
|
|
||||||
public function processLandRequest(
|
|
||||||
AphrontRequest $request,
|
|
||||||
DifferentialRevision $revision,
|
|
||||||
PhabricatorRepository $repository) {
|
|
||||||
|
|
||||||
$viewer = $request->getUser();
|
|
||||||
$workspace = $this->getGitWorkspace($repository);
|
|
||||||
|
|
||||||
try {
|
|
||||||
$this->commitRevisionToWorkspace($revision, $workspace, $viewer);
|
|
||||||
} catch (Exception $e) {
|
|
||||||
throw new PhutilProxyException(
|
|
||||||
pht('Failed to commit patch.'),
|
|
||||||
$e);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
$this->pushWorkspaceRepository($repository, $workspace, $viewer);
|
|
||||||
} catch (Exception $e) {
|
|
||||||
throw new PhutilProxyException(
|
|
||||||
pht('Failed to push changes upstream.'),
|
|
||||||
$e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function commitRevisionToWorkspace(
|
|
||||||
DifferentialRevision $revision,
|
|
||||||
ArcanistRepositoryAPI $workspace,
|
|
||||||
PhabricatorUser $user) {
|
|
||||||
|
|
||||||
$diff_id = $revision->loadActiveDiff()->getID();
|
|
||||||
|
|
||||||
$call = new ConduitCall(
|
|
||||||
'differential.getrawdiff',
|
|
||||||
array(
|
|
||||||
'diffID' => $diff_id,
|
|
||||||
));
|
|
||||||
|
|
||||||
$call->setUser($user);
|
|
||||||
$raw_diff = $call->execute();
|
|
||||||
|
|
||||||
$missing_binary =
|
|
||||||
"\nindex "
|
|
||||||
."0000000000000000000000000000000000000000.."
|
|
||||||
."0000000000000000000000000000000000000000\n";
|
|
||||||
if (strpos($raw_diff, $missing_binary) !== false) {
|
|
||||||
throw new Exception(pht('Patch is missing content for a binary file'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$future = $workspace->execFutureLocal('apply --index -');
|
|
||||||
$future->write($raw_diff);
|
|
||||||
$future->resolvex();
|
|
||||||
|
|
||||||
$workspace->reloadWorkingCopy();
|
|
||||||
|
|
||||||
$call = new ConduitCall(
|
|
||||||
'differential.getcommitmessage',
|
|
||||||
array(
|
|
||||||
'revision_id' => $revision->getID(),
|
|
||||||
));
|
|
||||||
|
|
||||||
$call->setUser($user);
|
|
||||||
$message = $call->execute();
|
|
||||||
|
|
||||||
$author = id(new PhabricatorUser())->loadOneWhere(
|
|
||||||
'phid = %s',
|
|
||||||
$revision->getAuthorPHID());
|
|
||||||
|
|
||||||
$author_string = sprintf(
|
|
||||||
'%s <%s>',
|
|
||||||
$author->getRealName(),
|
|
||||||
$author->loadPrimaryEmailAddress());
|
|
||||||
$author_date = $revision->getDateCreated();
|
|
||||||
|
|
||||||
$workspace->execxLocal(
|
|
||||||
'-c user.name=%s -c user.email=%s '.
|
|
||||||
'commit --date=%s --author=%s '.
|
|
||||||
'--message=%s',
|
|
||||||
// -c will set the 'committer'
|
|
||||||
$user->getRealName(),
|
|
||||||
$user->loadPrimaryEmailAddress(),
|
|
||||||
$author_date,
|
|
||||||
$author_string,
|
|
||||||
$message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function pushWorkspaceRepository(
|
|
||||||
PhabricatorRepository $repository,
|
|
||||||
ArcanistRepositoryAPI $workspace,
|
|
||||||
PhabricatorUser $user) {
|
|
||||||
|
|
||||||
$workspace->execxLocal('push origin HEAD:master');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function createMenuItem(
|
|
||||||
PhabricatorUser $viewer,
|
|
||||||
DifferentialRevision $revision,
|
|
||||||
PhabricatorRepository $repository) {
|
|
||||||
|
|
||||||
$vcs = $repository->getVersionControlSystem();
|
|
||||||
if ($vcs !== PhabricatorRepositoryType::REPOSITORY_TYPE_GIT) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$repository->isHosted()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$repository->isWorkingCopyBare()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: This temporarily disables this action, because it doesn't work
|
|
||||||
// and is confusing to users. If you want to use it, comment out this line
|
|
||||||
// for now and we'll provide real support eventually.
|
|
||||||
return;
|
|
||||||
|
|
||||||
return $this->createActionView(
|
|
||||||
$revision,
|
|
||||||
pht('Land to Hosted Repository'));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,106 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
final class DifferentialHostedMercurialLandingStrategy
|
|
||||||
extends DifferentialLandingStrategy {
|
|
||||||
|
|
||||||
public function processLandRequest(
|
|
||||||
AphrontRequest $request,
|
|
||||||
DifferentialRevision $revision,
|
|
||||||
PhabricatorRepository $repository) {
|
|
||||||
|
|
||||||
$viewer = $request->getUser();
|
|
||||||
|
|
||||||
$workspace = $this->getMercurialWorkspace($repository);
|
|
||||||
|
|
||||||
try {
|
|
||||||
$this->commitRevisionToWorkspace($revision, $workspace, $viewer);
|
|
||||||
} catch (Exception $e) {
|
|
||||||
throw new PhutilProxyException(pht('Failed to commit patch.'), $e);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
$this->pushWorkspaceRepository($repository, $workspace, $viewer);
|
|
||||||
} catch (Exception $e) {
|
|
||||||
throw new PhutilProxyException(
|
|
||||||
pht('Failed to push changes upstream.'),
|
|
||||||
$e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function commitRevisionToWorkspace(
|
|
||||||
DifferentialRevision $revision,
|
|
||||||
ArcanistRepositoryAPI $workspace,
|
|
||||||
PhabricatorUser $user) {
|
|
||||||
|
|
||||||
$diff_id = $revision->loadActiveDiff()->getID();
|
|
||||||
|
|
||||||
$call = new ConduitCall(
|
|
||||||
'differential.getrawdiff',
|
|
||||||
array(
|
|
||||||
'diffID' => $diff_id,
|
|
||||||
));
|
|
||||||
|
|
||||||
$call->setUser($user);
|
|
||||||
$raw_diff = $call->execute();
|
|
||||||
|
|
||||||
$future = $workspace->execFutureLocal('patch --no-commit -');
|
|
||||||
$future->write($raw_diff);
|
|
||||||
$future->resolvex();
|
|
||||||
|
|
||||||
$workspace->reloadWorkingCopy();
|
|
||||||
|
|
||||||
$call = new ConduitCall(
|
|
||||||
'differential.getcommitmessage',
|
|
||||||
array(
|
|
||||||
'revision_id' => $revision->getID(),
|
|
||||||
));
|
|
||||||
|
|
||||||
$call->setUser($user);
|
|
||||||
$message = $call->execute();
|
|
||||||
|
|
||||||
$author = id(new PhabricatorUser())->loadOneWhere(
|
|
||||||
'phid = %s',
|
|
||||||
$revision->getAuthorPHID());
|
|
||||||
|
|
||||||
$author_string = sprintf(
|
|
||||||
'%s <%s>',
|
|
||||||
$author->getRealName(),
|
|
||||||
$author->loadPrimaryEmailAddress());
|
|
||||||
$author_date = $revision->getDateCreated();
|
|
||||||
|
|
||||||
$workspace->execxLocal(
|
|
||||||
'commit --date=%s --user=%s '.
|
|
||||||
'--message=%s',
|
|
||||||
$author_date.' 0',
|
|
||||||
$author_string,
|
|
||||||
$message);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public function pushWorkspaceRepository(
|
|
||||||
PhabricatorRepository $repository,
|
|
||||||
ArcanistRepositoryAPI $workspace,
|
|
||||||
PhabricatorUser $user) {
|
|
||||||
|
|
||||||
$workspace->execxLocal('push -b default');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function createMenuItem(
|
|
||||||
PhabricatorUser $viewer,
|
|
||||||
DifferentialRevision $revision,
|
|
||||||
PhabricatorRepository $repository) {
|
|
||||||
|
|
||||||
$vcs = $repository->getVersionControlSystem();
|
|
||||||
if ($vcs !== PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$repository->isHosted()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->createActionView(
|
|
||||||
$revision,
|
|
||||||
pht('Land to Hosted Repository'));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,81 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class adds a "Land this" button to revision view.
|
|
||||||
*/
|
|
||||||
final class DifferentialLandingActionMenuEventListener
|
|
||||||
extends PhabricatorEventListener {
|
|
||||||
|
|
||||||
public function register() {
|
|
||||||
$this->listen(PhabricatorEventType::TYPE_UI_DIDRENDERACTIONS);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function handleEvent(PhutilEvent $event) {
|
|
||||||
switch ($event->getType()) {
|
|
||||||
case PhabricatorEventType::TYPE_UI_DIDRENDERACTIONS:
|
|
||||||
$this->handleActionsEvent($event);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function handleActionsEvent(PhutilEvent $event) {
|
|
||||||
$object = $event->getValue('object');
|
|
||||||
if ($object instanceof DifferentialRevision) {
|
|
||||||
$this->renderRevisionAction($event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function renderRevisionAction(PhutilEvent $event) {
|
|
||||||
$viewer = $event->getUser();
|
|
||||||
|
|
||||||
if (!$this->canUseApplication($viewer)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$revision = $event->getValue('object');
|
|
||||||
|
|
||||||
$repository = $revision->getRepository();
|
|
||||||
if ($repository === null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($repository->canPerformAutomation()) {
|
|
||||||
$revision_id = $revision->getID();
|
|
||||||
|
|
||||||
$op = new DrydockLandRepositoryOperation();
|
|
||||||
$barrier = $op->getBarrierToLanding($viewer, $revision);
|
|
||||||
|
|
||||||
if ($barrier) {
|
|
||||||
$can_land = false;
|
|
||||||
} else {
|
|
||||||
$can_land = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
$action = id(new PhabricatorActionView())
|
|
||||||
->setName(pht('Land Revision'))
|
|
||||||
->setIcon('fa-fighter-jet')
|
|
||||||
->setHref("/differential/revision/operation/{$revision_id}/")
|
|
||||||
->setWorkflow(true)
|
|
||||||
->setDisabled(!$can_land);
|
|
||||||
|
|
||||||
|
|
||||||
$this->addActionMenuItems($event, $action);
|
|
||||||
}
|
|
||||||
|
|
||||||
$strategies = id(new PhutilClassMapQuery())
|
|
||||||
->setAncestorClass('DifferentialLandingStrategy')
|
|
||||||
->execute();
|
|
||||||
|
|
||||||
foreach ($strategies as $strategy) {
|
|
||||||
$action = $strategy->createMenuItem($viewer, $revision, $repository);
|
|
||||||
if ($action == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if ($strategy->isActionDisabled($viewer, $revision, $repository)) {
|
|
||||||
$action->setDisabled(true);
|
|
||||||
}
|
|
||||||
$this->addActionMenuItems($event, $action);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,87 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
abstract class DifferentialLandingStrategy extends Phobject {
|
|
||||||
|
|
||||||
abstract public function processLandRequest(
|
|
||||||
AphrontRequest $request,
|
|
||||||
DifferentialRevision $revision,
|
|
||||||
PhabricatorRepository $repository);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return PhabricatorActionView or null.
|
|
||||||
*/
|
|
||||||
abstract public function createMenuItem(
|
|
||||||
PhabricatorUser $viewer,
|
|
||||||
DifferentialRevision $revision,
|
|
||||||
PhabricatorRepository $repository);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return PhabricatorActionView which can be attached to the revision view.
|
|
||||||
*/
|
|
||||||
protected function createActionView($revision, $name) {
|
|
||||||
$strategy = get_class($this);
|
|
||||||
$revision_id = $revision->getId();
|
|
||||||
return id(new PhabricatorActionView())
|
|
||||||
->setRenderAsForm(true)
|
|
||||||
->setWorkflow(true)
|
|
||||||
->setName($name)
|
|
||||||
->setHref("/differential/revision/land/{$revision_id}/{$strategy}/");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if this action should be disabled, and explain why.
|
|
||||||
*
|
|
||||||
* By default, this method checks for push permissions, and for the
|
|
||||||
* revision being Accepted.
|
|
||||||
*
|
|
||||||
* @return False for "not disabled"; human-readable text explaining why, if
|
|
||||||
* it is disabled.
|
|
||||||
*/
|
|
||||||
public function isActionDisabled(
|
|
||||||
PhabricatorUser $viewer,
|
|
||||||
DifferentialRevision $revision,
|
|
||||||
PhabricatorRepository $repository) {
|
|
||||||
|
|
||||||
$status = $revision->getStatus();
|
|
||||||
if ($status != ArcanistDifferentialRevisionStatus::ACCEPTED) {
|
|
||||||
return pht('Only Accepted revisions can be landed.');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!PhabricatorPolicyFilter::hasCapability(
|
|
||||||
$viewer,
|
|
||||||
$repository,
|
|
||||||
DiffusionPushCapability::CAPABILITY)) {
|
|
||||||
return pht('You do not have permissions to push to this repository.');
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Might break if repository is not Git.
|
|
||||||
*/
|
|
||||||
protected function getGitWorkspace(PhabricatorRepository $repository) {
|
|
||||||
try {
|
|
||||||
return DifferentialGetWorkingCopy::getCleanGitWorkspace($repository);
|
|
||||||
} catch (Exception $e) {
|
|
||||||
throw new PhutilProxyException(
|
|
||||||
pht('Failed to allocate a workspace.'),
|
|
||||||
$e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Might break if repository is not Mercurial.
|
|
||||||
*/
|
|
||||||
protected function getMercurialWorkspace(PhabricatorRepository $repository) {
|
|
||||||
try {
|
|
||||||
return DifferentialGetWorkingCopy::getCleanMercurialWorkspace(
|
|
||||||
$repository);
|
|
||||||
} catch (Exception $e) {
|
|
||||||
throw new PhutilProxyException(
|
|
||||||
pht('Failed to allocate a workspace.'),
|
|
||||||
$e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1045,7 +1045,8 @@ final class DifferentialChangesetParser extends Phobject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->comments = $this->reorderAndThreadComments($this->comments);
|
$this->comments = id(new PHUIDiffInlineThreader())
|
||||||
|
->reorderAndThreadCommments($this->comments);
|
||||||
|
|
||||||
foreach ($this->comments as $comment) {
|
foreach ($this->comments as $comment) {
|
||||||
$final = $comment->getLineNumber() +
|
$final = $comment->getLineNumber() +
|
||||||
|
@ -1617,68 +1618,6 @@ final class DifferentialChangesetParser extends Phobject {
|
||||||
return array($old_back, $new_back);
|
return array($old_back, $new_back);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function reorderAndThreadComments(array $comments) {
|
|
||||||
$comments = msort($comments, 'getID');
|
|
||||||
|
|
||||||
// Build an empty map of all the comments we actually have. If a comment
|
|
||||||
// is a reply but the parent has gone missing, we don't want it to vanish
|
|
||||||
// completely.
|
|
||||||
$comment_phids = mpull($comments, 'getPHID');
|
|
||||||
$replies = array_fill_keys($comment_phids, array());
|
|
||||||
|
|
||||||
// Now, remove all comments which are replies, leaving only the top-level
|
|
||||||
// comments.
|
|
||||||
foreach ($comments as $key => $comment) {
|
|
||||||
$reply_phid = $comment->getReplyToCommentPHID();
|
|
||||||
if (isset($replies[$reply_phid])) {
|
|
||||||
$replies[$reply_phid][] = $comment;
|
|
||||||
unset($comments[$key]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// For each top level comment, add the comment, then add any replies
|
|
||||||
// to it. Do this recursively so threads are shown in threaded order.
|
|
||||||
$results = array();
|
|
||||||
foreach ($comments as $comment) {
|
|
||||||
$results[] = $comment;
|
|
||||||
$phid = $comment->getPHID();
|
|
||||||
$descendants = $this->getInlineReplies($replies, $phid, 1);
|
|
||||||
foreach ($descendants as $descendant) {
|
|
||||||
$results[] = $descendant;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we have anything left, they were cyclic references. Just dump
|
|
||||||
// them in a the end. This should be impossible, but users are very
|
|
||||||
// creative.
|
|
||||||
foreach ($replies as $phid => $comments) {
|
|
||||||
foreach ($comments as $comment) {
|
|
||||||
$results[] = $comment;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $results;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function getInlineReplies(array &$replies, $phid, $depth) {
|
|
||||||
$comments = idx($replies, $phid, array());
|
|
||||||
unset($replies[$phid]);
|
|
||||||
|
|
||||||
$results = array();
|
|
||||||
foreach ($comments as $comment) {
|
|
||||||
$results[] = $comment;
|
|
||||||
$descendants = $this->getInlineReplies(
|
|
||||||
$replies,
|
|
||||||
$comment->getPHID(),
|
|
||||||
$depth + 1);
|
|
||||||
foreach ($descendants as $descendant) {
|
|
||||||
$results[] = $descendant;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $results;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function getOffset(array $map, $line) {
|
private function getOffset(array $map, $line) {
|
||||||
if (!$map) {
|
if (!$map) {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -255,6 +255,13 @@ final class DifferentialInlineComment
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getDateModified() {
|
||||||
|
return $this->proxy->getDateModified();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDateCreated() {
|
||||||
|
return $this->proxy->getDateCreated();
|
||||||
|
}
|
||||||
|
|
||||||
/* -( PhabricatorMarkupInterface Implementation )-------------------------- */
|
/* -( PhabricatorMarkupInterface Implementation )-------------------------- */
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@ final class DifferentialChangesetListView extends AphrontView {
|
||||||
private $standaloneURI;
|
private $standaloneURI;
|
||||||
private $leftRawFileURI;
|
private $leftRawFileURI;
|
||||||
private $rightRawFileURI;
|
private $rightRawFileURI;
|
||||||
|
private $inlineListURI;
|
||||||
|
|
||||||
private $symbolIndexes = array();
|
private $symbolIndexes = array();
|
||||||
private $repository;
|
private $repository;
|
||||||
|
@ -64,6 +65,15 @@ final class DifferentialChangesetListView extends AphrontView {
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setInlineListURI($uri) {
|
||||||
|
$this->inlineListURI = $uri;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getInlineListURI() {
|
||||||
|
return $this->inlineListURI;
|
||||||
|
}
|
||||||
|
|
||||||
public function setRepository(PhabricatorRepository $repository) {
|
public function setRepository(PhabricatorRepository $repository) {
|
||||||
$this->repository = $repository;
|
$this->repository = $repository;
|
||||||
return $this;
|
return $this;
|
||||||
|
@ -208,6 +218,7 @@ final class DifferentialChangesetListView extends AphrontView {
|
||||||
array(
|
array(
|
||||||
'changesetViewIDs' => $ids,
|
'changesetViewIDs' => $ids,
|
||||||
'inlineURI' => $this->inlineURI,
|
'inlineURI' => $this->inlineURI,
|
||||||
|
'inlineListURI' => $this->inlineListURI,
|
||||||
'pht' => array(
|
'pht' => array(
|
||||||
'Open in Editor' => pht('Open in Editor'),
|
'Open in Editor' => pht('Open in Editor'),
|
||||||
'Show All Context' => pht('Show All Context'),
|
'Show All Context' => pht('Show All Context'),
|
||||||
|
@ -257,15 +268,15 @@ final class DifferentialChangesetListView extends AphrontView {
|
||||||
'You must select a comment to mark done.' =>
|
'You must select a comment to mark done.' =>
|
||||||
pht('You must select a comment to mark done.'),
|
pht('You must select a comment to mark done.'),
|
||||||
|
|
||||||
'Hide or show inline comment.' =>
|
'Collapse or expand inline comment.' =>
|
||||||
pht('Hide or show inline comment.'),
|
pht('Collapse or expand inline comment.'),
|
||||||
'You must select a comment to hide.' =>
|
'You must select a comment to hide.' =>
|
||||||
pht('You must select a comment to hide.'),
|
pht('You must select a comment to hide.'),
|
||||||
|
|
||||||
'Jump to next inline comment, including hidden comments.' =>
|
'Jump to next inline comment, including collapsed comments.' =>
|
||||||
pht('Jump to next inline comment, including hidden comments.'),
|
pht('Jump to next inline comment, including collapsed comments.'),
|
||||||
'Jump to previous inline comment, including hidden comments.' =>
|
'Jump to previous inline comment, including collapsed comments.' =>
|
||||||
pht('Jump to previous inline comment, including hidden comments.'),
|
pht('Jump to previous inline comment, including collapsed comments.'),
|
||||||
|
|
||||||
'This file content has been collapsed.' =>
|
'This file content has been collapsed.' =>
|
||||||
pht('This file content has been collapsed.'),
|
pht('This file content has been collapsed.'),
|
||||||
|
@ -279,6 +290,14 @@ final class DifferentialChangesetListView extends AphrontView {
|
||||||
'Unsaved' => pht('Unsaved'),
|
'Unsaved' => pht('Unsaved'),
|
||||||
'Unsubmitted' => pht('Unsubmitted'),
|
'Unsubmitted' => pht('Unsubmitted'),
|
||||||
'Comments' => pht('Comments'),
|
'Comments' => pht('Comments'),
|
||||||
|
|
||||||
|
'Hide "Done" Inlines' => pht('Hide "Done" Inlines'),
|
||||||
|
'Hide Collapsed Inlines' => pht('Hide Collapsed Inlines'),
|
||||||
|
'Hide Older Inlines' => pht('Hide Older Inlines'),
|
||||||
|
'Hide All Inlines' => pht('Hide All Inlines'),
|
||||||
|
'Show All Inlines' => pht('Show All Inlines'),
|
||||||
|
|
||||||
|
'List Inline Comments' => pht('List Inline Comments'),
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,7 @@ final class PhabricatorDiffusionApplication extends PhabricatorApplication {
|
||||||
'repository/(?P<dblob>.*)' => 'DiffusionRepositoryController',
|
'repository/(?P<dblob>.*)' => 'DiffusionRepositoryController',
|
||||||
'change/(?P<dblob>.*)' => 'DiffusionChangeController',
|
'change/(?P<dblob>.*)' => 'DiffusionChangeController',
|
||||||
'history/(?P<dblob>.*)' => 'DiffusionHistoryController',
|
'history/(?P<dblob>.*)' => 'DiffusionHistoryController',
|
||||||
|
'graph/(?P<dblob>.*)' => 'DiffusionGraphController',
|
||||||
'browse/(?P<dblob>.*)' => 'DiffusionBrowseController',
|
'browse/(?P<dblob>.*)' => 'DiffusionBrowseController',
|
||||||
'lastmodified/(?P<dblob>.*)' => 'DiffusionLastModifiedController',
|
'lastmodified/(?P<dblob>.*)' => 'DiffusionLastModifiedController',
|
||||||
'diff/' => 'DiffusionDiffController',
|
'diff/' => 'DiffusionDiffController',
|
||||||
|
@ -140,6 +141,8 @@ final class PhabricatorDiffusionApplication extends PhabricatorApplication {
|
||||||
$this->getEditRoutePattern('edit/') =>
|
$this->getEditRoutePattern('edit/') =>
|
||||||
'DiffusionCommitEditController',
|
'DiffusionCommitEditController',
|
||||||
),
|
),
|
||||||
|
'picture/(?P<id>[0-9]\d*)/'
|
||||||
|
=> 'DiffusionRepositoryProfilePictureController',
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,7 +48,7 @@ final class DiffusionBranchTableController extends DiffusionController {
|
||||||
->withRepository($repository)
|
->withRepository($repository)
|
||||||
->execute();
|
->execute();
|
||||||
|
|
||||||
$table = id(new DiffusionBranchTableView())
|
$list = id(new DiffusionBranchListView())
|
||||||
->setUser($viewer)
|
->setUser($viewer)
|
||||||
->setBranches($branches)
|
->setBranches($branches)
|
||||||
->setCommits($commits)
|
->setCommits($commits)
|
||||||
|
@ -57,7 +57,7 @@ final class DiffusionBranchTableController extends DiffusionController {
|
||||||
$content = id(new PHUIObjectBoxView())
|
$content = id(new PHUIObjectBoxView())
|
||||||
->setHeaderText($repository->getName())
|
->setHeaderText($repository->getName())
|
||||||
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
||||||
->setTable($table)
|
->setTable($list)
|
||||||
->setPager($pager);
|
->setPager($pager);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,10 +84,7 @@ final class DiffusionBranchTableController extends DiffusionController {
|
||||||
$repository->getDisplayName(),
|
$repository->getDisplayName(),
|
||||||
))
|
))
|
||||||
->setCrumbs($crumbs)
|
->setCrumbs($crumbs)
|
||||||
->appendChild(
|
->appendChild($view);
|
||||||
array(
|
|
||||||
$view,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -204,6 +204,9 @@ abstract class DiffusionController extends PhabricatorController {
|
||||||
case 'history':
|
case 'history':
|
||||||
$view_name = pht('History');
|
$view_name = pht('History');
|
||||||
break;
|
break;
|
||||||
|
case 'graph':
|
||||||
|
$view_name = pht('Graph');
|
||||||
|
break;
|
||||||
case 'browse':
|
case 'browse':
|
||||||
$view_name = pht('Browse');
|
$view_name = pht('Browse');
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -0,0 +1,108 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class DiffusionGraphController extends DiffusionController {
|
||||||
|
|
||||||
|
public function shouldAllowPublic() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handleRequest(AphrontRequest $request) {
|
||||||
|
$response = $this->loadDiffusionContext();
|
||||||
|
if ($response) {
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
$drequest = $this->getDiffusionRequest();
|
||||||
|
$repository = $drequest->getRepository();
|
||||||
|
|
||||||
|
$pager = id(new PHUIPagerView())
|
||||||
|
->readFromRequest($request);
|
||||||
|
|
||||||
|
$params = array(
|
||||||
|
'commit' => $drequest->getCommit(),
|
||||||
|
'path' => $drequest->getPath(),
|
||||||
|
'offset' => $pager->getOffset(),
|
||||||
|
'limit' => $pager->getPageSize() + 1,
|
||||||
|
);
|
||||||
|
|
||||||
|
$history_results = $this->callConduitWithDiffusionRequest(
|
||||||
|
'diffusion.historyquery',
|
||||||
|
$params);
|
||||||
|
$history = DiffusionPathChange::newFromConduit(
|
||||||
|
$history_results['pathChanges']);
|
||||||
|
|
||||||
|
$history = $pager->sliceResults($history);
|
||||||
|
|
||||||
|
$graph = id(new DiffusionHistoryTableView())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->setDiffusionRequest($drequest)
|
||||||
|
->setHistory($history);
|
||||||
|
|
||||||
|
$graph->loadRevisions();
|
||||||
|
$show_graph = !strlen($drequest->getPath());
|
||||||
|
if ($show_graph) {
|
||||||
|
$graph->setParents($history_results['parents']);
|
||||||
|
$graph->setIsHead(!$pager->getOffset());
|
||||||
|
$graph->setIsTail(!$pager->getHasMorePages());
|
||||||
|
}
|
||||||
|
|
||||||
|
$header = $this->buildHeader($drequest);
|
||||||
|
|
||||||
|
$crumbs = $this->buildCrumbs(
|
||||||
|
array(
|
||||||
|
'branch' => true,
|
||||||
|
'path' => true,
|
||||||
|
'view' => 'graph',
|
||||||
|
));
|
||||||
|
$crumbs->setBorder(true);
|
||||||
|
|
||||||
|
$title = array(
|
||||||
|
pht('Graph'),
|
||||||
|
$repository->getDisplayName(),
|
||||||
|
);
|
||||||
|
|
||||||
|
$graph_view = id(new PHUIObjectBoxView())
|
||||||
|
->setHeaderText(pht('History Graph'))
|
||||||
|
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
||||||
|
->setTable($graph)
|
||||||
|
->setPager($pager);
|
||||||
|
|
||||||
|
$view = id(new PHUITwoColumnView())
|
||||||
|
->setHeader($header)
|
||||||
|
->setFooter($graph_view);
|
||||||
|
|
||||||
|
return $this->newPage()
|
||||||
|
->setTitle($title)
|
||||||
|
->setCrumbs($crumbs)
|
||||||
|
->appendChild($view);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function buildHeader(DiffusionRequest $drequest) {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
$tag = $this->renderCommitHashTag($drequest);
|
||||||
|
$history_uri = $drequest->generateURI(
|
||||||
|
array(
|
||||||
|
'action' => 'history',
|
||||||
|
));
|
||||||
|
|
||||||
|
$history_button = id(new PHUIButtonView())
|
||||||
|
->setTag('a')
|
||||||
|
->setText(pht('History'))
|
||||||
|
->setHref($history_uri)
|
||||||
|
->setIcon('fa-history');
|
||||||
|
|
||||||
|
$header = id(new PHUIHeaderView())
|
||||||
|
->setUser($viewer)
|
||||||
|
->setPolicyObject($drequest->getRepository())
|
||||||
|
->addTag($tag)
|
||||||
|
->setHeader($this->renderPathLinks($drequest, $mode = 'history'))
|
||||||
|
->setHeaderIcon('fa-code-fork')
|
||||||
|
->addActionLink($history_button);
|
||||||
|
|
||||||
|
return $header;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -77,24 +77,28 @@ final class DiffusionHistoryController extends DiffusionController {
|
||||||
$viewer = $this->getViewer();
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
$tag = $this->renderCommitHashTag($drequest);
|
$tag = $this->renderCommitHashTag($drequest);
|
||||||
$browse_uri = $drequest->generateURI(
|
$show_graph = !strlen($drequest->getPath());
|
||||||
array(
|
|
||||||
'action' => 'browse',
|
|
||||||
));
|
|
||||||
|
|
||||||
$browse_button = id(new PHUIButtonView())
|
|
||||||
->setTag('a')
|
|
||||||
->setText(pht('Browse'))
|
|
||||||
->setHref($browse_uri)
|
|
||||||
->setIcon('fa-code');
|
|
||||||
|
|
||||||
$header = id(new PHUIHeaderView())
|
$header = id(new PHUIHeaderView())
|
||||||
->setUser($viewer)
|
->setUser($viewer)
|
||||||
->setPolicyObject($drequest->getRepository())
|
->setPolicyObject($drequest->getRepository())
|
||||||
->addTag($tag)
|
->addTag($tag)
|
||||||
->setHeader($this->renderPathLinks($drequest, $mode = 'history'))
|
->setHeader($this->renderPathLinks($drequest, $mode = 'history'))
|
||||||
->setHeaderIcon('fa-clock-o')
|
->setHeaderIcon('fa-clock-o');
|
||||||
->addActionLink($browse_button);
|
|
||||||
|
if ($show_graph) {
|
||||||
|
$graph_uri = $drequest->generateURI(
|
||||||
|
array(
|
||||||
|
'action' => 'graph',
|
||||||
|
));
|
||||||
|
|
||||||
|
$graph_button = id(new PHUIButtonView())
|
||||||
|
->setTag('a')
|
||||||
|
->setText(pht('Graph'))
|
||||||
|
->setHref($graph_uri)
|
||||||
|
->setIcon('fa-code-fork');
|
||||||
|
$header->addActionLink($graph_button);
|
||||||
|
}
|
||||||
|
|
||||||
return $header;
|
return $header;
|
||||||
|
|
||||||
|
|
|
@ -274,7 +274,9 @@ final class DiffusionRepositoryController extends DiffusionController {
|
||||||
->setHeader($repository->getName())
|
->setHeader($repository->getName())
|
||||||
->setUser($viewer)
|
->setUser($viewer)
|
||||||
->setPolicyObject($repository)
|
->setPolicyObject($repository)
|
||||||
->setHeaderIcon('fa-code');
|
->setProfileHeader(true)
|
||||||
|
->setImage($repository->getProfileImageURI())
|
||||||
|
->setImageEditURL('/diffusion/picture/'.$repository->getID().'/');
|
||||||
|
|
||||||
if (!$repository->isTracked()) {
|
if (!$repository->isTracked()) {
|
||||||
$header->setStatus('fa-ban', 'dark', pht('Inactive'));
|
$header->setStatus('fa-ban', 'dark', pht('Inactive'));
|
||||||
|
@ -449,11 +451,11 @@ final class DiffusionRepositoryController extends DiffusionController {
|
||||||
$header->setSubheader(pht('Showing %d branches.', $limit));
|
$header->setSubheader(pht('Showing %d branches.', $limit));
|
||||||
}
|
}
|
||||||
|
|
||||||
$button = new PHUIButtonView();
|
$button = id(new PHUIButtonView())
|
||||||
$button->setText(pht('Show All'));
|
->setText(pht('Show All'))
|
||||||
$button->setTag('a');
|
->setTag('a')
|
||||||
$button->setIcon('fa-code-fork');
|
->setIcon('fa-code-fork')
|
||||||
$button->setHref($drequest->generateURI(
|
->setHref($drequest->generateURI(
|
||||||
array(
|
array(
|
||||||
'action' => 'branches',
|
'action' => 'branches',
|
||||||
)));
|
)));
|
||||||
|
@ -490,7 +492,7 @@ final class DiffusionRepositoryController extends DiffusionController {
|
||||||
->needCommitData(true)
|
->needCommitData(true)
|
||||||
->execute();
|
->execute();
|
||||||
|
|
||||||
$view = id(new DiffusionTagListView())
|
$view = id(new DiffusionTagTableView())
|
||||||
->setUser($viewer)
|
->setUser($viewer)
|
||||||
->setDiffusionRequest($drequest)
|
->setDiffusionRequest($drequest)
|
||||||
->setTags($tags)
|
->setTags($tags)
|
||||||
|
@ -509,11 +511,11 @@ final class DiffusionRepositoryController extends DiffusionController {
|
||||||
pht('Showing the %d most recent tags.', $tag_limit));
|
pht('Showing the %d most recent tags.', $tag_limit));
|
||||||
}
|
}
|
||||||
|
|
||||||
$button = new PHUIButtonView();
|
$button = id(new PHUIButtonView())
|
||||||
$button->setText(pht('Show All Tags'));
|
->setText(pht('Show All Tags'))
|
||||||
$button->setTag('a');
|
->setTag('a')
|
||||||
$button->setIcon('fa-tag');
|
->setIcon('fa-tag')
|
||||||
$button->setHref($drequest->generateURI(
|
->setHref($drequest->generateURI(
|
||||||
array(
|
array(
|
||||||
'action' => 'tags',
|
'action' => 'tags',
|
||||||
)));
|
)));
|
||||||
|
@ -565,23 +567,30 @@ final class DiffusionRepositoryController extends DiffusionController {
|
||||||
|
|
||||||
$history_table->setIsHead(true);
|
$history_table->setIsHead(true);
|
||||||
|
|
||||||
$icon = id(new PHUIIconView())
|
$history = id(new PHUIButtonView())
|
||||||
->setIcon('fa-list-alt');
|
->setText(pht('History'))
|
||||||
|
|
||||||
$button = id(new PHUIButtonView())
|
|
||||||
->setText(pht('View History'))
|
|
||||||
->setHref($drequest->generateURI(
|
->setHref($drequest->generateURI(
|
||||||
array(
|
array(
|
||||||
'action' => 'history',
|
'action' => 'history',
|
||||||
)))
|
)))
|
||||||
->setTag('a')
|
->setTag('a')
|
||||||
->setIcon($icon);
|
->setIcon('fa-history');
|
||||||
|
|
||||||
|
$graph = id(new PHUIButtonView())
|
||||||
|
->setText(pht('Graph'))
|
||||||
|
->setHref($drequest->generateURI(
|
||||||
|
array(
|
||||||
|
'action' => 'graph',
|
||||||
|
)))
|
||||||
|
->setTag('a')
|
||||||
|
->setIcon('fa-code-fork');
|
||||||
|
|
||||||
$panel = id(new PHUIObjectBoxView())
|
$panel = id(new PHUIObjectBoxView())
|
||||||
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY);
|
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY);
|
||||||
$header = id(new PHUIHeaderView())
|
$header = id(new PHUIHeaderView())
|
||||||
->setHeader(pht('Recent Commits'))
|
->setHeader(pht('Recent Commits'))
|
||||||
->addActionLink($button);
|
->addActionLink($graph)
|
||||||
|
->addActionLink($history);
|
||||||
$panel->setHeader($header);
|
$panel->setHeader($header);
|
||||||
$panel->setTable($history_table);
|
$panel->setTable($history_table);
|
||||||
|
|
||||||
|
@ -670,14 +679,11 @@ final class DiffusionRepositoryController extends DiffusionController {
|
||||||
$header = id(new PHUIHeaderView())
|
$header = id(new PHUIHeaderView())
|
||||||
->setHeader($repository->getName());
|
->setHeader($repository->getName());
|
||||||
|
|
||||||
$icon = id(new PHUIIconView())
|
$button = id(new PHUIButtonView())
|
||||||
->setIcon('fa-folder-open');
|
->setText(pht('Browse'))
|
||||||
|
->setTag('a')
|
||||||
$button = new PHUIButtonView();
|
->setIcon('fa-code')
|
||||||
$button->setText(pht('Browse Repository'));
|
->setHref($browse_uri);
|
||||||
$button->setTag('a');
|
|
||||||
$button->setIcon($icon);
|
|
||||||
$button->setHref($browse_uri);
|
|
||||||
|
|
||||||
$header->addActionLink($button);
|
$header->addActionLink($button);
|
||||||
$browse_panel->setHeader($header);
|
$browse_panel->setHeader($header);
|
||||||
|
|
|
@ -0,0 +1,246 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class DiffusionRepositoryProfilePictureController
|
||||||
|
extends DiffusionController {
|
||||||
|
|
||||||
|
public function handleRequest(AphrontRequest $request) {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
$id = $request->getURIData('id');
|
||||||
|
|
||||||
|
$repository = id(new PhabricatorRepositoryQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withIDs(array($id))
|
||||||
|
->needProfileImage(true)
|
||||||
|
->needURIs(true)
|
||||||
|
->requireCapabilities(
|
||||||
|
array(
|
||||||
|
PhabricatorPolicyCapability::CAN_VIEW,
|
||||||
|
PhabricatorPolicyCapability::CAN_EDIT,
|
||||||
|
))
|
||||||
|
->executeOne();
|
||||||
|
|
||||||
|
if (!$repository) {
|
||||||
|
return new Aphront404Response();
|
||||||
|
}
|
||||||
|
|
||||||
|
$supported_formats = PhabricatorFile::getTransformableImageFormats();
|
||||||
|
$e_file = true;
|
||||||
|
$errors = array();
|
||||||
|
$done_uri = $repository->getURI();
|
||||||
|
|
||||||
|
if ($request->isFormPost()) {
|
||||||
|
$phid = $request->getStr('phid');
|
||||||
|
$is_default = false;
|
||||||
|
if ($phid == PhabricatorPHIDConstants::PHID_VOID) {
|
||||||
|
$phid = null;
|
||||||
|
$is_default = true;
|
||||||
|
} else if ($phid) {
|
||||||
|
$file = id(new PhabricatorFileQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withPHIDs(array($phid))
|
||||||
|
->executeOne();
|
||||||
|
} else {
|
||||||
|
if ($request->getFileExists('picture')) {
|
||||||
|
$file = PhabricatorFile::newFromPHPUpload(
|
||||||
|
$_FILES['picture'],
|
||||||
|
array(
|
||||||
|
'authorPHID' => $viewer->getPHID(),
|
||||||
|
'canCDN' => true,
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
$e_file = pht('Required');
|
||||||
|
$errors[] = pht(
|
||||||
|
'You must choose a file when uploading a new profile picture.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$errors && !$is_default) {
|
||||||
|
if (!$file->isTransformableImage()) {
|
||||||
|
$e_file = pht('Not Supported');
|
||||||
|
$errors[] = pht(
|
||||||
|
'This server only supports these image formats: %s.',
|
||||||
|
implode(', ', $supported_formats));
|
||||||
|
} else {
|
||||||
|
$xform = PhabricatorFileTransform::getTransformByKey(
|
||||||
|
PhabricatorFileThumbnailTransform::TRANSFORM_PROFILE);
|
||||||
|
$xformed = $xform->executeTransform($file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$errors) {
|
||||||
|
if ($is_default) {
|
||||||
|
$repository->setProfileImagePHID(null);
|
||||||
|
} else {
|
||||||
|
$repository->setProfileImagePHID($xformed->getPHID());
|
||||||
|
$xformed->attachToObject($repository->getPHID());
|
||||||
|
}
|
||||||
|
$repository->save();
|
||||||
|
return id(new AphrontRedirectResponse())->setURI($done_uri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$title = pht('Edit Picture');
|
||||||
|
|
||||||
|
$form = id(new PHUIFormLayoutView())
|
||||||
|
->setUser($viewer);
|
||||||
|
|
||||||
|
$default_image = PhabricatorFile::loadBuiltin(
|
||||||
|
$viewer, 'repo/code.png');
|
||||||
|
|
||||||
|
$images = array();
|
||||||
|
|
||||||
|
$current = $repository->getProfileImagePHID();
|
||||||
|
$has_current = false;
|
||||||
|
if ($current) {
|
||||||
|
$files = id(new PhabricatorFileQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withPHIDs(array($current))
|
||||||
|
->execute();
|
||||||
|
if ($files) {
|
||||||
|
$file = head($files);
|
||||||
|
if ($file->isTransformableImage()) {
|
||||||
|
$has_current = true;
|
||||||
|
$images[$current] = array(
|
||||||
|
'uri' => $file->getBestURI(),
|
||||||
|
'tip' => pht('Current Picture'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$builtins = array(
|
||||||
|
'repo/building.png',
|
||||||
|
'repo/cloud.png',
|
||||||
|
'repo/commit.png',
|
||||||
|
'repo/database.png',
|
||||||
|
'repo/desktop.png',
|
||||||
|
'repo/gears.png',
|
||||||
|
'repo/globe.png',
|
||||||
|
'repo/locked.png',
|
||||||
|
'repo/microchip.png',
|
||||||
|
'repo/mobile.png',
|
||||||
|
'repo/repo.png',
|
||||||
|
'repo/servers.png',
|
||||||
|
);
|
||||||
|
foreach ($builtins as $builtin) {
|
||||||
|
$file = PhabricatorFile::loadBuiltin($viewer, $builtin);
|
||||||
|
$images[$file->getPHID()] = array(
|
||||||
|
'uri' => $file->getBestURI(),
|
||||||
|
'tip' => pht('Builtin Image'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$images[PhabricatorPHIDConstants::PHID_VOID] = array(
|
||||||
|
'uri' => $default_image->getBestURI(),
|
||||||
|
'tip' => pht('Default Picture'),
|
||||||
|
);
|
||||||
|
|
||||||
|
require_celerity_resource('people-profile-css');
|
||||||
|
Javelin::initBehavior('phabricator-tooltips', array());
|
||||||
|
|
||||||
|
$buttons = array();
|
||||||
|
foreach ($images as $phid => $spec) {
|
||||||
|
$style = null;
|
||||||
|
if (isset($spec['style'])) {
|
||||||
|
$style = $spec['style'];
|
||||||
|
}
|
||||||
|
$button = javelin_tag(
|
||||||
|
'button',
|
||||||
|
array(
|
||||||
|
'class' => 'button-grey profile-image-button',
|
||||||
|
'sigil' => 'has-tooltip',
|
||||||
|
'meta' => array(
|
||||||
|
'tip' => $spec['tip'],
|
||||||
|
'size' => 300,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
phutil_tag(
|
||||||
|
'img',
|
||||||
|
array(
|
||||||
|
'height' => 50,
|
||||||
|
'width' => 50,
|
||||||
|
'src' => $spec['uri'],
|
||||||
|
)));
|
||||||
|
|
||||||
|
$button = array(
|
||||||
|
phutil_tag(
|
||||||
|
'input',
|
||||||
|
array(
|
||||||
|
'type' => 'hidden',
|
||||||
|
'name' => 'phid',
|
||||||
|
'value' => $phid,
|
||||||
|
)),
|
||||||
|
$button,
|
||||||
|
);
|
||||||
|
|
||||||
|
$button = phabricator_form(
|
||||||
|
$viewer,
|
||||||
|
array(
|
||||||
|
'class' => 'profile-image-form',
|
||||||
|
'method' => 'POST',
|
||||||
|
),
|
||||||
|
$button);
|
||||||
|
|
||||||
|
$buttons[] = $button;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($has_current) {
|
||||||
|
$form->appendChild(
|
||||||
|
id(new AphrontFormMarkupControl())
|
||||||
|
->setLabel(pht('Current Picture'))
|
||||||
|
->setValue(array_shift($buttons)));
|
||||||
|
}
|
||||||
|
|
||||||
|
$form->appendChild(
|
||||||
|
id(new AphrontFormMarkupControl())
|
||||||
|
->setLabel(pht('Use Picture'))
|
||||||
|
->setValue($buttons));
|
||||||
|
|
||||||
|
$form_box = id(new PHUIObjectBoxView())
|
||||||
|
->setHeaderText($title)
|
||||||
|
->setFormErrors($errors)
|
||||||
|
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
||||||
|
->setForm($form);
|
||||||
|
|
||||||
|
$upload_form = id(new AphrontFormView())
|
||||||
|
->setUser($viewer)
|
||||||
|
->setEncType('multipart/form-data')
|
||||||
|
->appendChild(
|
||||||
|
id(new AphrontFormFileControl())
|
||||||
|
->setName('picture')
|
||||||
|
->setLabel(pht('Upload Picture'))
|
||||||
|
->setError($e_file)
|
||||||
|
->setCaption(
|
||||||
|
pht('Supported formats: %s', implode(', ', $supported_formats))))
|
||||||
|
->appendChild(
|
||||||
|
id(new AphrontFormSubmitControl())
|
||||||
|
->addCancelButton($done_uri)
|
||||||
|
->setValue(pht('Upload Picture')));
|
||||||
|
|
||||||
|
$header = id(new PHUIHeaderView())
|
||||||
|
->setHeader(pht('Edit Repository Picture'))
|
||||||
|
->setHeaderIcon('fa-camera-retro');
|
||||||
|
|
||||||
|
$crumbs = $this->buildApplicationCrumbs();
|
||||||
|
$crumbs->addTextCrumb($repository->getName(), $repository->getURI());
|
||||||
|
$crumbs->addTextCrumb(pht('Edit Picture'));
|
||||||
|
$crumbs->setBorder(true);
|
||||||
|
|
||||||
|
$upload_box = id(new PHUIObjectBoxView())
|
||||||
|
->setHeaderText(pht('Upload New Picture'))
|
||||||
|
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
||||||
|
->setForm($upload_form);
|
||||||
|
|
||||||
|
$view = id(new PHUITwoColumnView())
|
||||||
|
->setHeader($header)
|
||||||
|
->setFooter(array(
|
||||||
|
$form_box,
|
||||||
|
$upload_box,
|
||||||
|
));
|
||||||
|
|
||||||
|
return $this->newPage()
|
||||||
|
->setTitle($title)
|
||||||
|
->setCrumbs($crumbs)
|
||||||
|
->appendChild($view);
|
||||||
|
}
|
||||||
|
}
|
|
@ -64,17 +64,21 @@ final class DiffusionTagListController extends DiffusionController {
|
||||||
->needCommitData(true)
|
->needCommitData(true)
|
||||||
->execute();
|
->execute();
|
||||||
|
|
||||||
$view = id(new DiffusionTagListView())
|
$tag_list = id(new DiffusionTagListView())
|
||||||
->setTags($tags)
|
->setTags($tags)
|
||||||
->setUser($viewer)
|
->setUser($viewer)
|
||||||
->setCommits($commits)
|
->setCommits($commits)
|
||||||
->setDiffusionRequest($drequest);
|
->setDiffusionRequest($drequest);
|
||||||
|
|
||||||
$phids = $view->getRequiredHandlePHIDs();
|
$phids = $tag_list->getRequiredHandlePHIDs();
|
||||||
$handles = $this->loadViewerHandles($phids);
|
$handles = $this->loadViewerHandles($phids);
|
||||||
$view->setHandles($handles);
|
$tag_list->setHandles($handles);
|
||||||
|
|
||||||
$content = $view;
|
$content = id(new PHUIObjectBoxView())
|
||||||
|
->setHeaderText($repository->getDisplayName())
|
||||||
|
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
||||||
|
->setTable($tag_list)
|
||||||
|
->setPager($pager);
|
||||||
}
|
}
|
||||||
|
|
||||||
$crumbs = $this->buildCrumbs(
|
$crumbs = $this->buildCrumbs(
|
||||||
|
@ -84,17 +88,9 @@ final class DiffusionTagListController extends DiffusionController {
|
||||||
));
|
));
|
||||||
$crumbs->setBorder(true);
|
$crumbs->setBorder(true);
|
||||||
|
|
||||||
$box = id(new PHUIObjectBoxView())
|
|
||||||
->setHeaderText($repository->getDisplayName())
|
|
||||||
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
|
||||||
->setTable($view)
|
|
||||||
->setPager($pager);
|
|
||||||
|
|
||||||
$view = id(new PHUITwoColumnView())
|
$view = id(new PHUITwoColumnView())
|
||||||
->setHeader($header)
|
->setHeader($header)
|
||||||
->setFooter(array(
|
->setFooter($content);
|
||||||
$box,
|
|
||||||
));
|
|
||||||
|
|
||||||
return $this->newPage()
|
return $this->newPage()
|
||||||
->setTitle(
|
->setTitle(
|
||||||
|
@ -103,7 +99,8 @@ final class DiffusionTagListController extends DiffusionController {
|
||||||
$repository->getDisplayName(),
|
$repository->getDisplayName(),
|
||||||
))
|
))
|
||||||
->setCrumbs($crumbs)
|
->setCrumbs($crumbs)
|
||||||
->appendChild($view);
|
->appendChild($view)
|
||||||
|
->addClass('diffusion-history-view');
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -143,6 +143,7 @@ abstract class DiffusionRequest extends Phobject {
|
||||||
$query = id(new PhabricatorRepositoryQuery())
|
$query = id(new PhabricatorRepositoryQuery())
|
||||||
->setViewer($viewer)
|
->setViewer($viewer)
|
||||||
->withIdentifiers(array($identifier))
|
->withIdentifiers(array($identifier))
|
||||||
|
->needProfileImage(true)
|
||||||
->needURIs(true);
|
->needURIs(true);
|
||||||
|
|
||||||
if ($need_edit) {
|
if ($need_edit) {
|
||||||
|
|
138
src/applications/diffusion/view/DiffusionBranchListView.php
Normal file
|
@ -0,0 +1,138 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class DiffusionBranchListView extends DiffusionView {
|
||||||
|
|
||||||
|
private $branches;
|
||||||
|
private $commits = array();
|
||||||
|
|
||||||
|
public function setBranches(array $branches) {
|
||||||
|
assert_instances_of($branches, 'DiffusionRepositoryRef');
|
||||||
|
$this->branches = $branches;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setCommits(array $commits) {
|
||||||
|
assert_instances_of($commits, 'PhabricatorRepositoryCommit');
|
||||||
|
$this->commits = mpull($commits, null, 'getCommitIdentifier');
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function render() {
|
||||||
|
$drequest = $this->getDiffusionRequest();
|
||||||
|
$current_branch = $drequest->getBranch();
|
||||||
|
$repository = $drequest->getRepository();
|
||||||
|
$commits = $this->commits;
|
||||||
|
$viewer = $this->getUser();
|
||||||
|
require_celerity_resource('diffusion-history-css');
|
||||||
|
|
||||||
|
$buildables = $this->loadBuildables($commits);
|
||||||
|
$have_builds = false;
|
||||||
|
|
||||||
|
$can_close_branches = ($repository->isHg());
|
||||||
|
|
||||||
|
Javelin::initBehavior('phabricator-tooltips');
|
||||||
|
|
||||||
|
$doc_href = PhabricatorEnv::getDoclink('Diffusion User Guide: Autoclose');
|
||||||
|
$list = id(new PHUIObjectItemListView())
|
||||||
|
->setFlush(true)
|
||||||
|
->addClass('diffusion-history-list')
|
||||||
|
->addClass('diffusion-branch-list');
|
||||||
|
|
||||||
|
foreach ($this->branches as $branch) {
|
||||||
|
$build_view = null;
|
||||||
|
$button_bar = new PHUIButtonBarView();
|
||||||
|
$commit = idx($commits, $branch->getCommitIdentifier());
|
||||||
|
if ($commit) {
|
||||||
|
$details = $commit->getSummary();
|
||||||
|
$datetime = phabricator_datetime($commit->getEpoch(), $viewer);
|
||||||
|
|
||||||
|
$buildable = idx($buildables, $commit->getPHID());
|
||||||
|
if ($buildable) {
|
||||||
|
$build_view = $this->renderBuildable($buildable, 'button');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$datetime = null;
|
||||||
|
$details = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($repository->supportsBranchComparison()) {
|
||||||
|
$compare_uri = $drequest->generateURI(
|
||||||
|
array(
|
||||||
|
'action' => 'compare',
|
||||||
|
'head' => $branch->getShortName(),
|
||||||
|
));
|
||||||
|
$can_compare = ($branch->getShortName() != $current_branch);
|
||||||
|
if ($can_compare) {
|
||||||
|
$button_bar->addButton(
|
||||||
|
id(new PHUIButtonView())
|
||||||
|
->setTag('a')
|
||||||
|
->setIcon('fa-balance-scale')
|
||||||
|
->setToolTip(pht('Compare'))
|
||||||
|
->setButtonType(PHUIButtonView::BUTTONTYPE_SIMPLE)
|
||||||
|
->setWorkflow(true)
|
||||||
|
->setHref($compare_uri));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$fields = $branch->getRawFields();
|
||||||
|
$closed = idx($fields, 'closed');
|
||||||
|
if ($closed) {
|
||||||
|
$status = pht('Closed');
|
||||||
|
} else {
|
||||||
|
$status = pht('Open');
|
||||||
|
}
|
||||||
|
|
||||||
|
$browse_href = $drequest->generateURI(
|
||||||
|
array(
|
||||||
|
'action' => 'browse',
|
||||||
|
'branch' => $branch->getShortName(),
|
||||||
|
));
|
||||||
|
|
||||||
|
$button_bar->addButton(
|
||||||
|
id(new PHUIButtonView())
|
||||||
|
->setIcon('fa-code')
|
||||||
|
->setHref($browse_href)
|
||||||
|
->setTag('a')
|
||||||
|
->setTooltip(pht('Browse'))
|
||||||
|
->setButtonType(PHUIButtonView::BUTTONTYPE_SIMPLE));
|
||||||
|
|
||||||
|
$commit_link = $repository->getCommitURI(
|
||||||
|
$branch->getCommitIdentifier());
|
||||||
|
|
||||||
|
$commit_name = $repository->formatCommitName(
|
||||||
|
$branch->getCommitIdentifier(), $local = true);
|
||||||
|
|
||||||
|
$commit_tag = id(new PHUITagView())
|
||||||
|
->setName($commit_name)
|
||||||
|
->setHref($commit_link)
|
||||||
|
->setType(PHUITagView::TYPE_SHADE)
|
||||||
|
->setColor(PHUITagView::COLOR_INDIGO)
|
||||||
|
->setBorder(PHUITagView::BORDER_NONE)
|
||||||
|
->setSlimShady(true);
|
||||||
|
$subhead = array($commit_tag, ' ', $details);
|
||||||
|
|
||||||
|
$item = id(new PHUIObjectItemView())
|
||||||
|
->setHeader($branch->getShortName())
|
||||||
|
->setHref($drequest->generateURI(
|
||||||
|
array(
|
||||||
|
'action' => 'history',
|
||||||
|
'branch' => $branch->getShortName(),
|
||||||
|
)))
|
||||||
|
->setSubhead($subhead)
|
||||||
|
->setSideColumn(array(
|
||||||
|
$build_view,
|
||||||
|
$button_bar,
|
||||||
|
));
|
||||||
|
|
||||||
|
if ($branch->getShortName() == $repository->getDefaultBranch()) {
|
||||||
|
$item->setStatusIcon('fa-code-fork', pht('Default Branch'));
|
||||||
|
}
|
||||||
|
$item->addAttribute(array($datetime));
|
||||||
|
|
||||||
|
$list->addItem($item);
|
||||||
|
|
||||||
|
}
|
||||||
|
return $list;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -119,19 +119,7 @@ final class DiffusionHistoryListView extends DiffusionHistoryView {
|
||||||
if ($show_builds) {
|
if ($show_builds) {
|
||||||
$buildable = idx($buildables, $commit->getPHID());
|
$buildable = idx($buildables, $commit->getPHID());
|
||||||
if ($buildable !== null) {
|
if ($buildable !== null) {
|
||||||
$status = $buildable->getBuildableStatus();
|
$build_view = $this->renderBuildable($buildable, 'button');
|
||||||
$icon = HarbormasterBuildable::getBuildableStatusIcon($status);
|
|
||||||
$color = HarbormasterBuildable::getBuildableStatusColor($status);
|
|
||||||
$name = HarbormasterBuildable::getBuildableStatusName($status);
|
|
||||||
$build_view = id(new PHUIButtonView())
|
|
||||||
->setTag('a')
|
|
||||||
->setText($name)
|
|
||||||
->setIcon($icon)
|
|
||||||
->setColor($color)
|
|
||||||
->setHref('/'.$buildable->getMonogram())
|
|
||||||
->addClass('mmr')
|
|
||||||
->setButtonType(PHUIButtonView::BUTTONTYPE_SIMPLE)
|
|
||||||
->addClass('diffusion-list-build-status');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,36 +29,28 @@ final class DiffusionTagListView extends DiffusionView {
|
||||||
$drequest = $this->getDiffusionRequest();
|
$drequest = $this->getDiffusionRequest();
|
||||||
$repository = $drequest->getRepository();
|
$repository = $drequest->getRepository();
|
||||||
$viewer = $this->getViewer();
|
$viewer = $this->getViewer();
|
||||||
|
require_celerity_resource('diffusion-history-css');
|
||||||
|
|
||||||
$buildables = $this->loadBuildables($this->commits);
|
$buildables = $this->loadBuildables($this->commits);
|
||||||
$has_builds = false;
|
|
||||||
|
|
||||||
$rows = array();
|
$list = id(new PHUIObjectItemListView())
|
||||||
|
->setFlush(true)
|
||||||
|
->addClass('diffusion-history-list');
|
||||||
foreach ($this->tags as $tag) {
|
foreach ($this->tags as $tag) {
|
||||||
$commit = idx($this->commits, $tag->getCommitIdentifier());
|
$commit = idx($this->commits, $tag->getCommitIdentifier());
|
||||||
|
$button_bar = new PHUIButtonBarView();
|
||||||
|
|
||||||
$tag_link = phutil_tag(
|
$tag_href = $drequest->generateURI(
|
||||||
'a',
|
|
||||||
array(
|
array(
|
||||||
'href' => $drequest->generateURI(
|
'action' => 'history',
|
||||||
array(
|
|
||||||
'action' => 'browse',
|
|
||||||
'commit' => $tag->getName(),
|
'commit' => $tag->getName(),
|
||||||
)),
|
));
|
||||||
),
|
|
||||||
$tag->getName());
|
|
||||||
|
|
||||||
$commit_link = phutil_tag(
|
$commit_href = $drequest->generateURI(
|
||||||
'a',
|
|
||||||
array(
|
|
||||||
'href' => $drequest->generateURI(
|
|
||||||
array(
|
array(
|
||||||
'action' => 'commit',
|
'action' => 'commit',
|
||||||
'commit' => $tag->getCommitIdentifier(),
|
'commit' => $tag->getCommitIdentifier(),
|
||||||
)),
|
));
|
||||||
),
|
|
||||||
$repository->formatCommitName(
|
|
||||||
$tag->getCommitIdentifier()));
|
|
||||||
|
|
||||||
$author = null;
|
$author = null;
|
||||||
if ($commit && $commit->getAuthorPHID()) {
|
if ($commit && $commit->getAuthorPHID()) {
|
||||||
|
@ -69,6 +61,15 @@ final class DiffusionTagListView extends DiffusionView {
|
||||||
$author = self::renderName($tag->getAuthor());
|
$author = self::renderName($tag->getAuthor());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$committed = phabricator_datetime($commit->getEpoch(), $viewer);
|
||||||
|
$author_name = phutil_tag(
|
||||||
|
'strong',
|
||||||
|
array(
|
||||||
|
'class' => 'diffusion-history-author-name',
|
||||||
|
),
|
||||||
|
$author);
|
||||||
|
$authored = pht('%s on %s.', $author_name, $committed);
|
||||||
|
|
||||||
$description = null;
|
$description = null;
|
||||||
if ($tag->getType() == 'git/tag') {
|
if ($tag->getType() == 'git/tag') {
|
||||||
// In Git, a tag may be a "real" tag, or just a reference to a commit.
|
// In Git, a tag may be a "real" tag, or just a reference to a commit.
|
||||||
|
@ -83,58 +84,71 @@ final class DiffusionTagListView extends DiffusionView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$build = null;
|
$build_view = null;
|
||||||
if ($commit) {
|
if ($commit) {
|
||||||
$buildable = idx($buildables, $commit->getPHID());
|
$buildable = idx($buildables, $commit->getPHID());
|
||||||
if ($buildable) {
|
if ($buildable) {
|
||||||
$build = $this->renderBuildable($buildable);
|
$build_view = $this->renderBuildable($buildable, 'button');
|
||||||
$has_builds = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$history = $this->linkTagHistory($tag->getName());
|
if ($repository->supportsBranchComparison()) {
|
||||||
|
$compare_uri = $drequest->generateURI(
|
||||||
$rows[] = array(
|
|
||||||
$history,
|
|
||||||
$tag_link,
|
|
||||||
$commit_link,
|
|
||||||
$build,
|
|
||||||
$author,
|
|
||||||
$description,
|
|
||||||
$viewer->formatShortDateTime($tag->getEpoch()),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
$table = id(new AphrontTableView($rows))
|
|
||||||
->setHeaders(
|
|
||||||
array(
|
array(
|
||||||
null,
|
'action' => 'compare',
|
||||||
pht('Tag'),
|
'head' => $tag->getName(),
|
||||||
pht('Commit'),
|
|
||||||
null,
|
|
||||||
pht('Author'),
|
|
||||||
pht('Description'),
|
|
||||||
pht('Created'),
|
|
||||||
))
|
|
||||||
->setColumnClasses(
|
|
||||||
array(
|
|
||||||
'nudgeright',
|
|
||||||
'pri',
|
|
||||||
'',
|
|
||||||
'',
|
|
||||||
'',
|
|
||||||
'wide',
|
|
||||||
'right',
|
|
||||||
))
|
|
||||||
->setColumnVisibility(
|
|
||||||
array(
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
$has_builds,
|
|
||||||
));
|
));
|
||||||
|
|
||||||
return $table->render();
|
$button_bar->addButton(
|
||||||
|
id(new PHUIButtonView())
|
||||||
|
->setTag('a')
|
||||||
|
->setIcon('fa-balance-scale')
|
||||||
|
->setToolTip(pht('Compare'))
|
||||||
|
->setButtonType(PHUIButtonView::BUTTONTYPE_SIMPLE)
|
||||||
|
->setWorkflow(true)
|
||||||
|
->setHref($compare_uri));
|
||||||
|
}
|
||||||
|
|
||||||
|
$commit_name = $repository->formatCommitName(
|
||||||
|
$tag->getCommitIdentifier(), $local = true);
|
||||||
|
|
||||||
|
$browse_href = $drequest->generateURI(
|
||||||
|
array(
|
||||||
|
'action' => 'browse',
|
||||||
|
'commit' => $tag->getName(),
|
||||||
|
));
|
||||||
|
|
||||||
|
$button_bar->addButton(
|
||||||
|
id(new PHUIButtonView())
|
||||||
|
->setTooltip(pht('Browse'))
|
||||||
|
->setIcon('fa-code')
|
||||||
|
->setHref($browse_href)
|
||||||
|
->setTag('a')
|
||||||
|
->setButtonType(PHUIButtonView::BUTTONTYPE_SIMPLE));
|
||||||
|
|
||||||
|
$commit_tag = id(new PHUITagView())
|
||||||
|
->setName($commit_name)
|
||||||
|
->setHref($commit_href)
|
||||||
|
->setType(PHUITagView::TYPE_SHADE)
|
||||||
|
->setColor(PHUITagView::COLOR_INDIGO)
|
||||||
|
->setBorder(PHUITagView::BORDER_NONE)
|
||||||
|
->setSlimShady(true);
|
||||||
|
|
||||||
|
$item = id(new PHUIObjectItemView())
|
||||||
|
->setHeader($tag->getName())
|
||||||
|
->setHref($tag_href)
|
||||||
|
->addAttribute(array($commit_tag))
|
||||||
|
->addAttribute($description)
|
||||||
|
->addAttribute($authored)
|
||||||
|
->setSideColumn(array(
|
||||||
|
$build_view,
|
||||||
|
$button_bar,
|
||||||
|
));
|
||||||
|
|
||||||
|
$list->addItem($item);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $list;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
140
src/applications/diffusion/view/DiffusionTagTableView.php
Normal file
|
@ -0,0 +1,140 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class DiffusionTagTableView extends DiffusionView {
|
||||||
|
|
||||||
|
private $tags;
|
||||||
|
private $commits = array();
|
||||||
|
private $handles = array();
|
||||||
|
|
||||||
|
public function setTags($tags) {
|
||||||
|
$this->tags = $tags;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setCommits(array $commits) {
|
||||||
|
$this->commits = mpull($commits, null, 'getCommitIdentifier');
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setHandles(array $handles) {
|
||||||
|
$this->handles = $handles;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRequiredHandlePHIDs() {
|
||||||
|
return array_filter(mpull($this->commits, 'getAuthorPHID'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function render() {
|
||||||
|
$drequest = $this->getDiffusionRequest();
|
||||||
|
$repository = $drequest->getRepository();
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
$buildables = $this->loadBuildables($this->commits);
|
||||||
|
$has_builds = false;
|
||||||
|
|
||||||
|
$rows = array();
|
||||||
|
foreach ($this->tags as $tag) {
|
||||||
|
$commit = idx($this->commits, $tag->getCommitIdentifier());
|
||||||
|
|
||||||
|
$tag_link = phutil_tag(
|
||||||
|
'a',
|
||||||
|
array(
|
||||||
|
'href' => $drequest->generateURI(
|
||||||
|
array(
|
||||||
|
'action' => 'browse',
|
||||||
|
'commit' => $tag->getName(),
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
$tag->getName());
|
||||||
|
|
||||||
|
$commit_link = phutil_tag(
|
||||||
|
'a',
|
||||||
|
array(
|
||||||
|
'href' => $drequest->generateURI(
|
||||||
|
array(
|
||||||
|
'action' => 'commit',
|
||||||
|
'commit' => $tag->getCommitIdentifier(),
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
$repository->formatCommitName(
|
||||||
|
$tag->getCommitIdentifier()));
|
||||||
|
|
||||||
|
$author = null;
|
||||||
|
if ($commit && $commit->getAuthorPHID()) {
|
||||||
|
$author = $this->handles[$commit->getAuthorPHID()]->renderLink();
|
||||||
|
} else if ($commit && $commit->getCommitData()) {
|
||||||
|
$author = self::renderName($commit->getCommitData()->getAuthorName());
|
||||||
|
} else {
|
||||||
|
$author = self::renderName($tag->getAuthor());
|
||||||
|
}
|
||||||
|
|
||||||
|
$description = null;
|
||||||
|
if ($tag->getType() == 'git/tag') {
|
||||||
|
// In Git, a tag may be a "real" tag, or just a reference to a commit.
|
||||||
|
// If it's a real tag, use the message on the tag, since this may be
|
||||||
|
// unique data which isn't otherwise available.
|
||||||
|
$description = $tag->getDescription();
|
||||||
|
} else {
|
||||||
|
if ($commit) {
|
||||||
|
$description = $commit->getSummary();
|
||||||
|
} else {
|
||||||
|
$description = $tag->getDescription();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$build = null;
|
||||||
|
if ($commit) {
|
||||||
|
$buildable = idx($buildables, $commit->getPHID());
|
||||||
|
if ($buildable) {
|
||||||
|
$build = $this->renderBuildable($buildable);
|
||||||
|
$has_builds = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$history = $this->linkTagHistory($tag->getName());
|
||||||
|
|
||||||
|
$rows[] = array(
|
||||||
|
$history,
|
||||||
|
$tag_link,
|
||||||
|
$commit_link,
|
||||||
|
$build,
|
||||||
|
$author,
|
||||||
|
$description,
|
||||||
|
$viewer->formatShortDateTime($tag->getEpoch()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$table = id(new AphrontTableView($rows))
|
||||||
|
->setHeaders(
|
||||||
|
array(
|
||||||
|
null,
|
||||||
|
pht('Tag'),
|
||||||
|
pht('Commit'),
|
||||||
|
null,
|
||||||
|
pht('Author'),
|
||||||
|
pht('Description'),
|
||||||
|
pht('Created'),
|
||||||
|
))
|
||||||
|
->setColumnClasses(
|
||||||
|
array(
|
||||||
|
'nudgeright',
|
||||||
|
'pri',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
'wide',
|
||||||
|
'right',
|
||||||
|
))
|
||||||
|
->setColumnVisibility(
|
||||||
|
array(
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
$has_builds,
|
||||||
|
));
|
||||||
|
|
||||||
|
return $table->render();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -116,10 +116,10 @@ abstract class DiffusionView extends AphrontView {
|
||||||
|
|
||||||
if ($button) {
|
if ($button) {
|
||||||
return id(new PHUIButtonView())
|
return id(new PHUIButtonView())
|
||||||
->setText(pht('Browse'))
|
->setTag('a')
|
||||||
->setIcon('fa-code')
|
->setIcon('fa-code')
|
||||||
->setHref($href)
|
->setHref($href)
|
||||||
->setTag('a')
|
->setToolTip(pht('Browse'))
|
||||||
->setButtonType(PHUIButtonView::BUTTONTYPE_SIMPLE);
|
->setButtonType(PHUIButtonView::BUTTONTYPE_SIMPLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,7 +190,8 @@ abstract class DiffusionView extends AphrontView {
|
||||||
}
|
}
|
||||||
|
|
||||||
final protected function renderBuildable(
|
final protected function renderBuildable(
|
||||||
HarbormasterBuildable $buildable) {
|
HarbormasterBuildable $buildable,
|
||||||
|
$type = null) {
|
||||||
$status = $buildable->getBuildableStatus();
|
$status = $buildable->getBuildableStatus();
|
||||||
Javelin::initBehavior('phabricator-tooltips');
|
Javelin::initBehavior('phabricator-tooltips');
|
||||||
|
|
||||||
|
@ -198,6 +199,18 @@ abstract class DiffusionView extends AphrontView {
|
||||||
$color = HarbormasterBuildable::getBuildableStatusColor($status);
|
$color = HarbormasterBuildable::getBuildableStatusColor($status);
|
||||||
$name = HarbormasterBuildable::getBuildableStatusName($status);
|
$name = HarbormasterBuildable::getBuildableStatusName($status);
|
||||||
|
|
||||||
|
if ($type == 'button') {
|
||||||
|
return id(new PHUIButtonView())
|
||||||
|
->setTag('a')
|
||||||
|
->setText($name)
|
||||||
|
->setIcon($icon)
|
||||||
|
->setColor($color)
|
||||||
|
->setHref('/'.$buildable->getMonogram())
|
||||||
|
->addClass('mmr')
|
||||||
|
->setButtonType(PHUIButtonView::BUTTONTYPE_SIMPLE)
|
||||||
|
->addClass('diffusion-list-build-status');
|
||||||
|
}
|
||||||
|
|
||||||
return id(new PHUIIconView())
|
return id(new PHUIIconView())
|
||||||
->setIcon($icon.' '.$color)
|
->setIcon($icon.' '.$color)
|
||||||
->addSigil('has-tooltip')
|
->addSigil('has-tooltip')
|
||||||
|
|
|
@ -18,6 +18,7 @@ final class PhabricatorFileQuery
|
||||||
private $isDeleted;
|
private $isDeleted;
|
||||||
private $needTransforms;
|
private $needTransforms;
|
||||||
private $builtinKeys;
|
private $builtinKeys;
|
||||||
|
private $isBuiltin;
|
||||||
|
|
||||||
public function withIDs(array $ids) {
|
public function withIDs(array $ids) {
|
||||||
$this->ids = $ids;
|
$this->ids = $ids;
|
||||||
|
@ -54,6 +55,11 @@ final class PhabricatorFileQuery
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function withIsBuiltin($is_builtin) {
|
||||||
|
$this->isBuiltin = $is_builtin;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Select files which are transformations of some other file. For example,
|
* Select files which are transformations of some other file. For example,
|
||||||
* you can use this query to find previously generated thumbnails of an image
|
* you can use this query to find previously generated thumbnails of an image
|
||||||
|
@ -416,6 +422,18 @@ final class PhabricatorFileQuery
|
||||||
$this->builtinKeys);
|
$this->builtinKeys);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($this->isBuiltin !== null) {
|
||||||
|
if ($this->isBuiltin) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn,
|
||||||
|
'builtinKey IS NOT NULL');
|
||||||
|
} else {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn,
|
||||||
|
'builtinKey IS NULL');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return $where;
|
return $where;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -393,6 +393,7 @@ final class PhabricatorFile extends PhabricatorFileDAO
|
||||||
$tmp = new TempFile();
|
$tmp = new TempFile();
|
||||||
Filesystem::writeFile($tmp, $data);
|
Filesystem::writeFile($tmp, $data);
|
||||||
$file->setMimeType(Filesystem::getMimeType($tmp));
|
$file->setMimeType(Filesystem::getMimeType($tmp));
|
||||||
|
unset($tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -186,12 +186,18 @@ abstract class PhabricatorFileUploadSource
|
||||||
$actual_length = strlen($data);
|
$actual_length = strlen($data);
|
||||||
$rope->removeBytesFromHead($actual_length);
|
$rope->removeBytesFromHead($actual_length);
|
||||||
|
|
||||||
$chunk_data = PhabricatorFile::newFromFileData(
|
$params = array(
|
||||||
$data,
|
|
||||||
array(
|
|
||||||
'name' => $file->getMonogram().'.chunk-'.$offset,
|
'name' => $file->getMonogram().'.chunk-'.$offset,
|
||||||
'viewPolicy' => PhabricatorPolicies::POLICY_NOONE,
|
'viewPolicy' => PhabricatorPolicies::POLICY_NOONE,
|
||||||
));
|
);
|
||||||
|
|
||||||
|
// If this isn't the initial chunk, provide a dummy MIME type so we do not
|
||||||
|
// try to detect it. See T12857.
|
||||||
|
if ($offset > 0) {
|
||||||
|
$params['mime-type'] = 'application/octet-stream';
|
||||||
|
}
|
||||||
|
|
||||||
|
$chunk_data = PhabricatorFile::newFromFileData($data, $params);
|
||||||
|
|
||||||
$chunk = PhabricatorFileChunk::initializeNewChunk(
|
$chunk = PhabricatorFileChunk::initializeNewChunk(
|
||||||
$file->getStorageHandle(),
|
$file->getStorageHandle(),
|
||||||
|
@ -208,11 +214,17 @@ abstract class PhabricatorFileUploadSource
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getNewFileParameters() {
|
private function getNewFileParameters() {
|
||||||
return array(
|
$parameters = array(
|
||||||
'name' => $this->getName(),
|
'name' => $this->getName(),
|
||||||
'ttl.relative' => $this->getRelativeTTL(),
|
|
||||||
'viewPolicy' => $this->getViewPolicy(),
|
'viewPolicy' => $this->getViewPolicy(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$ttl = $this->getRelativeTTL();
|
||||||
|
if ($ttl !== null) {
|
||||||
|
$parameters['ttl.relative'] = $ttl;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $parameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getChunkEngine() {
|
private function getChunkEngine() {
|
||||||
|
|
|
@ -194,11 +194,14 @@ final class ManiphestTaskTestCase extends PhabricatorTestCase {
|
||||||
$dst,
|
$dst,
|
||||||
$is_after);
|
$is_after);
|
||||||
|
|
||||||
|
$keyword_map = ManiphestTaskPriority::getTaskPriorityKeywordsMap();
|
||||||
|
$keyword = head($keyword_map[$pri]);
|
||||||
|
|
||||||
$xactions = array();
|
$xactions = array();
|
||||||
|
|
||||||
$xactions[] = id(new ManiphestTransaction())
|
$xactions[] = id(new ManiphestTransaction())
|
||||||
->setTransactionType(ManiphestTaskPriorityTransaction::TRANSACTIONTYPE)
|
->setTransactionType(ManiphestTaskPriorityTransaction::TRANSACTIONTYPE)
|
||||||
->setNewValue($pri);
|
->setNewValue($keyword);
|
||||||
|
|
||||||
$xactions[] = id(new ManiphestTransaction())
|
$xactions[] = id(new ManiphestTransaction())
|
||||||
->setTransactionType(ManiphestTaskSubpriorityTransaction::TRANSACTIONTYPE)
|
->setTransactionType(ManiphestTaskSubpriorityTransaction::TRANSACTIONTYPE)
|
||||||
|
@ -217,11 +220,14 @@ final class ManiphestTaskTestCase extends PhabricatorTestCase {
|
||||||
$target_priority,
|
$target_priority,
|
||||||
$is_end);
|
$is_end);
|
||||||
|
|
||||||
|
$keyword_map = ManiphestTaskPriority::getTaskPriorityKeywordsMap();
|
||||||
|
$keyword = head($keyword_map[$pri]);
|
||||||
|
|
||||||
$xactions = array();
|
$xactions = array();
|
||||||
|
|
||||||
$xactions[] = id(new ManiphestTransaction())
|
$xactions[] = id(new ManiphestTransaction())
|
||||||
->setTransactionType(ManiphestTaskPriorityTransaction::TRANSACTIONTYPE)
|
->setTransactionType(ManiphestTaskPriorityTransaction::TRANSACTIONTYPE)
|
||||||
->setNewValue($pri);
|
->setNewValue($keyword);
|
||||||
|
|
||||||
$xactions[] = id(new ManiphestTransaction())
|
$xactions[] = id(new ManiphestTransaction())
|
||||||
->setTransactionType(ManiphestTaskSubpriorityTransaction::TRANSACTIONTYPE)
|
->setTransactionType(ManiphestTaskSubpriorityTransaction::TRANSACTIONTYPE)
|
||||||
|
|
|
@ -285,6 +285,11 @@ final class ManiphestTaskEditBulkJobType
|
||||||
'=' => array_fuse($value),
|
'=' => array_fuse($value),
|
||||||
));
|
));
|
||||||
break;
|
break;
|
||||||
|
case ManiphestTaskPriorityTransaction::TRANSACTIONTYPE:
|
||||||
|
$keyword_map = ManiphestTaskPriority::getTaskPriorityKeywordsMap();
|
||||||
|
$keyword = head(idx($keyword_map, $value));
|
||||||
|
$xaction->setNewValue($keyword);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
$xaction->setNewValue($value);
|
$xaction->setNewValue($value);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -49,18 +49,8 @@ final class ManiphestPriorityEmailCommand
|
||||||
array $argv) {
|
array $argv) {
|
||||||
$xactions = array();
|
$xactions = array();
|
||||||
|
|
||||||
$target = phutil_utf8_strtolower(head($argv));
|
$keyword = phutil_utf8_strtolower(head($argv));
|
||||||
$priority = null;
|
$priority = ManiphestTaskPriority::getTaskPriorityFromKeyword($keyword);
|
||||||
|
|
||||||
$keywords = ManiphestTaskPriority::getTaskPriorityKeywordsMap();
|
|
||||||
foreach ($keywords as $key => $words) {
|
|
||||||
foreach ($words as $word) {
|
|
||||||
if ($word == $target) {
|
|
||||||
$priority = $key;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($priority === null) {
|
if ($priority === null) {
|
||||||
return array();
|
return array();
|
||||||
|
@ -72,7 +62,7 @@ final class ManiphestPriorityEmailCommand
|
||||||
|
|
||||||
$xactions[] = $object->getApplicationTransactionTemplate()
|
$xactions[] = $object->getApplicationTransactionTemplate()
|
||||||
->setTransactionType(ManiphestTaskPriorityTransaction::TRANSACTIONTYPE)
|
->setTransactionType(ManiphestTaskPriorityTransaction::TRANSACTIONTYPE)
|
||||||
->setNewValue($priority);
|
->setNewValue($keyword);
|
||||||
|
|
||||||
return $xactions;
|
return $xactions;
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,7 +99,9 @@ abstract class ManiphestConduitAPIMethod extends ConduitAPIMethod {
|
||||||
throw id(new ConduitException('ERR-INVALID-PARAMETER'))
|
throw id(new ConduitException('ERR-INVALID-PARAMETER'))
|
||||||
->setErrorDescription(pht('Priority set to invalid value.'));
|
->setErrorDescription(pht('Priority set to invalid value.'));
|
||||||
}
|
}
|
||||||
$changes[ManiphestTaskPriorityTransaction::TRANSACTIONTYPE] = $priority;
|
$keyword_map = ManiphestTaskPriority::getTaskPriorityKeywordsMap();
|
||||||
|
$keyword = head(idx($keyword_map, $priority));
|
||||||
|
$changes[ManiphestTaskPriorityTransaction::TRANSACTIONTYPE] = $keyword;
|
||||||
}
|
}
|
||||||
|
|
||||||
$owner_phid = $request->getValue('ownerPHID');
|
$owner_phid = $request->getValue('ownerPHID');
|
||||||
|
|
|
@ -33,4 +33,14 @@ final class ManiphestQueryStatusesConduitAPIMethod
|
||||||
return $results;
|
return $results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getMethodStatus() {
|
||||||
|
return self::METHOD_STATUS_FROZEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMethodStatusDescription() {
|
||||||
|
return pht(
|
||||||
|
'This method is frozen and will eventually be deprecated. New code '.
|
||||||
|
'should use "maniphest.status.search" instead.');
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class ManiphestStatusSearchConduitAPIMethod
|
||||||
|
extends ManiphestConduitAPIMethod {
|
||||||
|
|
||||||
|
public function getAPIMethodName() {
|
||||||
|
return 'maniphest.status.search';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMethodSummary() {
|
||||||
|
return pht('Read information about task statuses.');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMethodDescription() {
|
||||||
|
return pht(
|
||||||
|
'Returns information about the possible statuses for Maniphest '.
|
||||||
|
'tasks.');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function defineParamTypes() {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function defineReturnType() {
|
||||||
|
return 'map<string, wild>';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRequiredScope() {
|
||||||
|
return self::SCOPE_ALWAYS;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function execute(ConduitAPIRequest $request) {
|
||||||
|
$config = PhabricatorEnv::getEnvConfig('maniphest.statuses');
|
||||||
|
$results = array();
|
||||||
|
foreach ($config as $code => $status) {
|
||||||
|
$stripped_status = array(
|
||||||
|
'name' => $status['name'],
|
||||||
|
'value' => $code,
|
||||||
|
'closed' => !empty($status['closed']),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isset($status['special'])) {
|
||||||
|
$stripped_status['special'] = $status['special'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$results[] = $stripped_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
return array('data' => $results);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
final class ManiphestTaskPriority extends ManiphestConstants {
|
final class ManiphestTaskPriority extends ManiphestConstants {
|
||||||
|
|
||||||
|
const UNKNOWN_PRIORITY_KEYWORD = '!!unknown!!';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the priorities and their full descriptions.
|
* Get the priorities and their full descriptions.
|
||||||
*
|
*
|
||||||
|
@ -41,6 +43,58 @@ final class ManiphestTaskPriority extends ManiphestConstants {
|
||||||
return $map;
|
return $map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the canonical keyword for a given priority constant.
|
||||||
|
*
|
||||||
|
* @return string|null Keyword, or `null` if no keyword is configured.
|
||||||
|
*/
|
||||||
|
public static function getKeywordForTaskPriority($priority) {
|
||||||
|
$map = self::getConfig();
|
||||||
|
|
||||||
|
$spec = idx($map, $priority);
|
||||||
|
if (!$spec) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$keywords = idx($spec, 'keywords');
|
||||||
|
if (!$keywords) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return head($keywords);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a map of supported alternate names for each priority.
|
||||||
|
*
|
||||||
|
* Keys are aliases, like "wish" and "wishlist". Values are canonical
|
||||||
|
* priority keywords, like "wishlist".
|
||||||
|
*
|
||||||
|
* @return map<string, string> Map of aliases to canonical priority keywords.
|
||||||
|
*/
|
||||||
|
public static function getTaskPriorityAliasMap() {
|
||||||
|
$keyword_map = self::getTaskPriorityKeywordsMap();
|
||||||
|
|
||||||
|
$result = array();
|
||||||
|
foreach ($keyword_map as $key => $keywords) {
|
||||||
|
$target = self::getKeywordForTaskPriority($key);
|
||||||
|
if ($target === null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: Include the raw priority value, like "25", in the list of
|
||||||
|
// aliases. This supports legacy sources like saved EditEngine forms.
|
||||||
|
$result[$key] = $target;
|
||||||
|
|
||||||
|
foreach ($keywords as $keyword) {
|
||||||
|
$result[$keyword] = $target;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the priorities and their related short (one-word) descriptions.
|
* Get the priorities and their related short (one-word) descriptions.
|
||||||
|
@ -105,6 +159,18 @@ final class ManiphestTaskPriority extends ManiphestConstants {
|
||||||
return 'fa-arrow-right';
|
return 'fa-arrow-right';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function getTaskPriorityFromKeyword($keyword) {
|
||||||
|
$map = self::getTaskPriorityKeywordsMap();
|
||||||
|
|
||||||
|
foreach ($map as $priority => $keywords) {
|
||||||
|
if (in_array($keyword, $keywords)) {
|
||||||
|
return $priority;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public static function isDisabledPriority($priority) {
|
public static function isDisabledPriority($priority) {
|
||||||
$config = idx(self::getConfig(), $priority, array());
|
$config = idx(self::getConfig(), $priority, array());
|
||||||
return idx($config, 'disabled', false);
|
return idx($config, 'disabled', false);
|
||||||
|
@ -116,6 +182,18 @@ final class ManiphestTaskPriority extends ManiphestConstants {
|
||||||
return $config;
|
return $config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static function isValidPriorityKeyword($keyword) {
|
||||||
|
if (!strlen($keyword) || strlen($keyword) > 64) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Alphanumeric, but not exclusively numeric
|
||||||
|
if (!preg_match('/^(?![0-9]*$)[a-zA-Z0-9]+$/', $keyword)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public static function validateConfiguration($config) {
|
public static function validateConfiguration($config) {
|
||||||
if (!is_array($config)) {
|
if (!is_array($config)) {
|
||||||
throw new Exception(
|
throw new Exception(
|
||||||
|
@ -147,9 +225,24 @@ final class ManiphestTaskPriority extends ManiphestConstants {
|
||||||
'name' => 'string',
|
'name' => 'string',
|
||||||
'short' => 'optional string',
|
'short' => 'optional string',
|
||||||
'color' => 'optional string',
|
'color' => 'optional string',
|
||||||
'keywords' => 'optional list<string>',
|
'keywords' => 'list<string>',
|
||||||
'disabled' => 'optional bool',
|
'disabled' => 'optional bool',
|
||||||
));
|
));
|
||||||
|
|
||||||
|
$keywords = $value['keywords'];
|
||||||
|
foreach ($keywords as $keyword) {
|
||||||
|
if (!self::isValidPriorityKeyword($keyword)) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'Key "%s" is not a valid priority keyword. Priority keywords '.
|
||||||
|
'must be 1-64 alphanumeric characters and cannot be '.
|
||||||
|
'exclusively digits. For example, "%s" or "%s" are '.
|
||||||
|
'reasonable choices.',
|
||||||
|
$keyword,
|
||||||
|
'low',
|
||||||
|
'critical'));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -232,16 +232,17 @@ final class ManiphestTaskStatus extends ManiphestConstants {
|
||||||
* @task validate
|
* @task validate
|
||||||
*/
|
*/
|
||||||
public static function isValidStatusConstant($constant) {
|
public static function isValidStatusConstant($constant) {
|
||||||
if (strlen($constant) > 12) {
|
if (!strlen($constant) || strlen($constant) > 64) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!preg_match('/^[a-z0-9]+\z/', $constant)) {
|
|
||||||
|
// Alphanumeric, but not exclusively numeric
|
||||||
|
if (!preg_match('/^(?![0-9]*$)[a-zA-Z0-9]+$/', $constant)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @task validate
|
* @task validate
|
||||||
*/
|
*/
|
||||||
|
@ -250,10 +251,9 @@ final class ManiphestTaskStatus extends ManiphestConstants {
|
||||||
if (!self::isValidStatusConstant($key)) {
|
if (!self::isValidStatusConstant($key)) {
|
||||||
throw new Exception(
|
throw new Exception(
|
||||||
pht(
|
pht(
|
||||||
'Key "%s" is not a valid status constant. Status constants must '.
|
'Key "%s" is not a valid status constant. Status constants '.
|
||||||
'be 1-12 characters long and contain only lowercase letters (a-z) '.
|
'must be 1-64 alphanumeric characters and cannot be exclusively '.
|
||||||
'and digits (0-9). For example, "%s" or "%s" are reasonable '.
|
'digits. For example, "%s" or "%s" are reasonable choices.',
|
||||||
'choices.',
|
|
||||||
$key,
|
$key,
|
||||||
'open',
|
'open',
|
||||||
'closed'));
|
'closed'));
|
||||||
|
|
|
@ -10,10 +10,15 @@ final class ManiphestTaskStatusTestCase extends PhabricatorTestCase {
|
||||||
'duplicate2' => true,
|
'duplicate2' => true,
|
||||||
|
|
||||||
'' => false,
|
'' => false,
|
||||||
'longlonglonglong' => false,
|
'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' =>
|
||||||
|
false,
|
||||||
'.' => false,
|
'.' => false,
|
||||||
'ABCD' => false,
|
' ' => false,
|
||||||
|
'ABCD' => true,
|
||||||
'a b c ' => false,
|
'a b c ' => false,
|
||||||
|
'1' => false,
|
||||||
|
'111' => false,
|
||||||
|
'11a' => true,
|
||||||
);
|
);
|
||||||
|
|
||||||
foreach ($map as $input => $expect) {
|
foreach ($map as $input => $expect) {
|
||||||
|
|
|
@ -40,11 +40,14 @@ final class ManiphestSubpriorityController extends ManiphestController {
|
||||||
$is_end = false);
|
$is_end = false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$keyword_map = ManiphestTaskPriority::getTaskPriorityKeywordsMap();
|
||||||
|
$keyword = head(idx($keyword_map, $pri));
|
||||||
|
|
||||||
$xactions = array();
|
$xactions = array();
|
||||||
|
|
||||||
$xactions[] = id(new ManiphestTransaction())
|
$xactions[] = id(new ManiphestTransaction())
|
||||||
->setTransactionType(ManiphestTaskPriorityTransaction::TRANSACTIONTYPE)
|
->setTransactionType(ManiphestTaskPriorityTransaction::TRANSACTIONTYPE)
|
||||||
->setNewValue($pri);
|
->setNewValue($keyword);
|
||||||
|
|
||||||
$xactions[] = id(new ManiphestTransaction())
|
$xactions[] = id(new ManiphestTransaction())
|
||||||
->setTransactionType(ManiphestTaskSubpriorityTransaction::TRANSACTIONTYPE)
|
->setTransactionType(ManiphestTaskSubpriorityTransaction::TRANSACTIONTYPE)
|
||||||
|
|
|
@ -77,6 +77,8 @@ final class ManiphestEditEngine
|
||||||
$status_map = $this->getTaskStatusMap($object);
|
$status_map = $this->getTaskStatusMap($object);
|
||||||
$priority_map = $this->getTaskPriorityMap($object);
|
$priority_map = $this->getTaskPriorityMap($object);
|
||||||
|
|
||||||
|
$alias_map = ManiphestTaskPriority::getTaskPriorityAliasMap();
|
||||||
|
|
||||||
if ($object->isClosed()) {
|
if ($object->isClosed()) {
|
||||||
$default_status = ManiphestTaskStatus::getDefaultStatus();
|
$default_status = ManiphestTaskStatus::getDefaultStatus();
|
||||||
} else {
|
} else {
|
||||||
|
@ -215,8 +217,9 @@ EODOCS
|
||||||
->setConduitTypeDescription(pht('New task priority constant.'))
|
->setConduitTypeDescription(pht('New task priority constant.'))
|
||||||
->setTransactionType(ManiphestTaskPriorityTransaction::TRANSACTIONTYPE)
|
->setTransactionType(ManiphestTaskPriorityTransaction::TRANSACTIONTYPE)
|
||||||
->setIsCopyable(true)
|
->setIsCopyable(true)
|
||||||
->setValue($object->getPriority())
|
->setValue($object->getPriorityKeyword())
|
||||||
->setOptions($priority_map)
|
->setOptions($priority_map)
|
||||||
|
->setOptionAliases($alias_map)
|
||||||
->setCommentActionLabel(pht('Change Priority')),
|
->setCommentActionLabel(pht('Change Priority')),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -289,29 +292,29 @@ EODOCS
|
||||||
|
|
||||||
private function getTaskPriorityMap(ManiphestTask $task) {
|
private function getTaskPriorityMap(ManiphestTask $task) {
|
||||||
$priority_map = ManiphestTaskPriority::getTaskPriorityMap();
|
$priority_map = ManiphestTaskPriority::getTaskPriorityMap();
|
||||||
|
$priority_keywords = ManiphestTaskPriority::getTaskPriorityKeywordsMap();
|
||||||
$current_priority = $task->getPriority();
|
$current_priority = $task->getPriority();
|
||||||
|
$results = array();
|
||||||
|
|
||||||
|
foreach ($priority_map as $priority => $priority_name) {
|
||||||
|
$disabled = ManiphestTaskPriority::isDisabledPriority($priority);
|
||||||
|
if ($disabled && !($priority == $current_priority)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$keyword = head(idx($priority_keywords, $priority));
|
||||||
|
$results[$keyword] = $priority_name;
|
||||||
|
}
|
||||||
|
|
||||||
// If the current value isn't a legitimate one, put it in the dropdown
|
// If the current value isn't a legitimate one, put it in the dropdown
|
||||||
// anyway so saving the form doesn't cause a side effects.
|
// anyway so saving the form doesn't cause any side effects.
|
||||||
if (idx($priority_map, $current_priority) === null) {
|
if (idx($priority_map, $current_priority) === null) {
|
||||||
$priority_map[$current_priority] = pht(
|
$results[ManiphestTaskPriority::UNKNOWN_PRIORITY_KEYWORD] = pht(
|
||||||
'<Unknown: %s>',
|
'<Unknown: %s>',
|
||||||
$current_priority);
|
$current_priority);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($priority_map as $priority => $priority_name) {
|
return $results;
|
||||||
// Always keep the current priority.
|
|
||||||
if ($priority == $current_priority) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ManiphestTaskPriority::isDisabledPriority($priority)) {
|
|
||||||
unset($priority_map[$priority]);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $priority_map;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function newEditResponse(
|
protected function newEditResponse(
|
||||||
|
|
|
@ -39,12 +39,15 @@ final class ManiphestTaskPriorityHeraldAction
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$keyword_map = ManiphestTaskPriority::getTaskPriorityKeywordsMap();
|
||||||
|
$keyword = head(idx($keyword_map, $priority));
|
||||||
|
|
||||||
$xaction = $adapter->newTransaction()
|
$xaction = $adapter->newTransaction()
|
||||||
->setTransactionType(ManiphestTaskPriorityTransaction::TRANSACTIONTYPE)
|
->setTransactionType(ManiphestTaskPriorityTransaction::TRANSACTIONTYPE)
|
||||||
->setNewValue($priority);
|
->setNewValue($keyword);
|
||||||
|
|
||||||
$adapter->queueTransaction($xaction);
|
$adapter->queueTransaction($xaction);
|
||||||
$this->logEffect(self::DO_PRIORITY, $priority);
|
$this->logEffect(self::DO_PRIORITY, $keyword);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getHeraldActionStandardType() {
|
public function getHeraldActionStandardType() {
|
||||||
|
|
|
@ -100,7 +100,10 @@ final class PhabricatorManiphestTaskTestDataGenerator
|
||||||
}
|
}
|
||||||
|
|
||||||
public function generateTaskPriority() {
|
public function generateTaskPriority() {
|
||||||
return array_rand(ManiphestTaskPriority::getTaskPriorityMap());
|
$pri = array_rand(ManiphestTaskPriority::getTaskPriorityMap());
|
||||||
|
$keyword_map = ManiphestTaskPriority::getTaskPriorityKeywordsMap();
|
||||||
|
$keyword = head(idx($keyword_map, $pri));
|
||||||
|
return $keyword;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function generateTaskSubPriority() {
|
public function generateTaskSubPriority() {
|
||||||
|
|
|
@ -79,7 +79,7 @@ final class ManiphestTask extends ManiphestDAO
|
||||||
),
|
),
|
||||||
self::CONFIG_COLUMN_SCHEMA => array(
|
self::CONFIG_COLUMN_SCHEMA => array(
|
||||||
'ownerPHID' => 'phid?',
|
'ownerPHID' => 'phid?',
|
||||||
'status' => 'text12',
|
'status' => 'text64',
|
||||||
'priority' => 'uint32',
|
'priority' => 'uint32',
|
||||||
'title' => 'sort',
|
'title' => 'sort',
|
||||||
'originalTitle' => 'text',
|
'originalTitle' => 'text',
|
||||||
|
@ -245,6 +245,17 @@ final class ManiphestTask extends ManiphestDAO
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getPriorityKeyword() {
|
||||||
|
$priority = $this->getPriority();
|
||||||
|
|
||||||
|
$keyword = ManiphestTaskPriority::getKeywordForTaskPriority($priority);
|
||||||
|
if ($keyword !== null) {
|
||||||
|
return $keyword;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ManiphestTaskPriority::UNKNOWN_PRIORITY_KEYWORD;
|
||||||
|
}
|
||||||
|
|
||||||
private function comparePriorityTo(ManiphestTask $other) {
|
private function comparePriorityTo(ManiphestTask $other) {
|
||||||
$upri = $this->getPriority();
|
$upri = $this->getPriority();
|
||||||
$vpri = $other->getPriority();
|
$vpri = $other->getPriority();
|
||||||
|
|
|
@ -12,6 +12,19 @@ final class ManiphestTaskPriorityTransaction
|
||||||
return $object->getPriority();
|
return $object->getPriority();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function generateNewValue($object, $value) {
|
||||||
|
// `$value` is supposed to be a keyword, but if the priority
|
||||||
|
// assigned to a task has been removed from the config,
|
||||||
|
// no such keyword will be available. Other edits to the task
|
||||||
|
// should still be allowed, even if the priority is no longer
|
||||||
|
// valid, so treat this as a no-op.
|
||||||
|
if ($value === ManiphestTaskPriority::UNKNOWN_PRIORITY_KEYWORD) {
|
||||||
|
return $object->getPriority();
|
||||||
|
}
|
||||||
|
|
||||||
|
return (string)ManiphestTaskPriority::getTaskPriorityFromKeyword($value);
|
||||||
|
}
|
||||||
|
|
||||||
public function applyInternalEffects($object, $value) {
|
public function applyInternalEffects($object, $value) {
|
||||||
$object->setPriority($value);
|
$object->setPriority($value);
|
||||||
}
|
}
|
||||||
|
@ -116,4 +129,50 @@ final class ManiphestTaskPriorityTransaction
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function validateTransactions($object, array $xactions) {
|
||||||
|
$errors = array();
|
||||||
|
|
||||||
|
$content_source = $this->getEditor()->getContentSource();
|
||||||
|
$is_web = ($content_source instanceof PhabricatorWebContentSource);
|
||||||
|
|
||||||
|
foreach ($xactions as $xaction) {
|
||||||
|
$value = $xaction->getNewValue();
|
||||||
|
|
||||||
|
// If this is a legitimate keyword like "low" or "high", this transaction
|
||||||
|
// is fine and apply normally.
|
||||||
|
$keyword = ManiphestTaskPriority::getTaskPriorityFromKeyword($value);
|
||||||
|
if ($keyword !== null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this is the magic "don't change things" value for editing tasks
|
||||||
|
// with an obsolete priority constant in the database, let it through if
|
||||||
|
// this is a web edit.
|
||||||
|
if ($value === ManiphestTaskPriority::UNKNOWN_PRIORITY_KEYWORD) {
|
||||||
|
if ($is_web) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$keyword_list = array();
|
||||||
|
foreach (ManiphestTaskPriority::getTaskPriorityMap() as $pri => $name) {
|
||||||
|
$keyword = ManiphestTaskPriority::getKeywordForTaskPriority($pri);
|
||||||
|
if ($keyword === null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$keyword_list[] = $keyword;
|
||||||
|
}
|
||||||
|
|
||||||
|
$errors[] = $this->newInvalidError(
|
||||||
|
pht(
|
||||||
|
'Task priority "%s" is not a valid task priority. Use a priority '.
|
||||||
|
'keyword to choose a task priority: %s.',
|
||||||
|
$value,
|
||||||
|
implode(', ', $keyword_list)),
|
||||||
|
$xaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $errors;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -372,6 +372,8 @@ final class PhabricatorMetaMTAMail
|
||||||
}
|
}
|
||||||
$editor->save();
|
$editor->save();
|
||||||
|
|
||||||
|
$this->saveTransaction();
|
||||||
|
|
||||||
// Queue a task to send this mail.
|
// Queue a task to send this mail.
|
||||||
$mailer_task = PhabricatorWorker::scheduleTask(
|
$mailer_task = PhabricatorWorker::scheduleTask(
|
||||||
'PhabricatorMetaMTAWorker',
|
'PhabricatorMetaMTAWorker',
|
||||||
|
@ -380,8 +382,6 @@ final class PhabricatorMetaMTAMail
|
||||||
'priority' => PhabricatorWorker::PRIORITY_ALERTS,
|
'priority' => PhabricatorWorker::PRIORITY_ALERTS,
|
||||||
));
|
));
|
||||||
|
|
||||||
$this->saveTransaction();
|
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -163,7 +163,7 @@ final class PhrictionDocumentQuery
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function buildJoinClauseParts(AphrontDatabaseConnection $conn) {
|
protected function buildJoinClauseParts(AphrontDatabaseConnection $conn) {
|
||||||
$joins = array();
|
$joins = parent::buildJoinClauseParts($conn);
|
||||||
|
|
||||||
if ($this->getOrderVector()->containsKey('updated')) {
|
if ($this->getOrderVector()->containsKey('updated')) {
|
||||||
$content_dao = new PhrictionContent();
|
$content_dao = new PhrictionContent();
|
||||||
|
|
|
@ -153,11 +153,14 @@ final class PhabricatorProjectMoveController
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$keyword_map = ManiphestTaskPriority::getTaskPriorityKeywordsMap();
|
||||||
|
$keyword = head(idx($keyword_map, $pri));
|
||||||
|
|
||||||
$xactions = array();
|
$xactions = array();
|
||||||
if ($pri !== null) {
|
if ($pri !== null) {
|
||||||
$xactions[] = id(new ManiphestTransaction())
|
$xactions[] = id(new ManiphestTransaction())
|
||||||
->setTransactionType(ManiphestTaskPriorityTransaction::TRANSACTIONTYPE)
|
->setTransactionType(ManiphestTaskPriorityTransaction::TRANSACTIONTYPE)
|
||||||
->setNewValue($pri);
|
->setNewValue($keyword);
|
||||||
$xactions[] = id(new ManiphestTransaction())
|
$xactions[] = id(new ManiphestTransaction())
|
||||||
->setTransactionType(
|
->setTransactionType(
|
||||||
ManiphestTaskSubpriorityTransaction::TRANSACTIONTYPE)
|
ManiphestTaskSubpriorityTransaction::TRANSACTIONTYPE)
|
||||||
|
|
|
@ -36,6 +36,7 @@ final class PhabricatorRepositoryQuery
|
||||||
private $needCommitCounts;
|
private $needCommitCounts;
|
||||||
private $needProjectPHIDs;
|
private $needProjectPHIDs;
|
||||||
private $needURIs;
|
private $needURIs;
|
||||||
|
private $needProfileImage;
|
||||||
|
|
||||||
public function withIDs(array $ids) {
|
public function withIDs(array $ids) {
|
||||||
$this->ids = $ids;
|
$this->ids = $ids;
|
||||||
|
@ -160,6 +161,11 @@ final class PhabricatorRepositoryQuery
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function needProfileImage($need) {
|
||||||
|
$this->needProfileImage = $need;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
public function getBuiltinOrders() {
|
public function getBuiltinOrders() {
|
||||||
return array(
|
return array(
|
||||||
'committed' => array(
|
'committed' => array(
|
||||||
|
@ -374,6 +380,36 @@ final class PhabricatorRepositoryQuery
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($this->needProfileImage) {
|
||||||
|
$default = null;
|
||||||
|
|
||||||
|
$file_phids = mpull($repositories, 'getProfileImagePHID');
|
||||||
|
$file_phids = array_filter($file_phids);
|
||||||
|
if ($file_phids) {
|
||||||
|
$files = id(new PhabricatorFileQuery())
|
||||||
|
->setParentQuery($this)
|
||||||
|
->setViewer($this->getViewer())
|
||||||
|
->withPHIDs($file_phids)
|
||||||
|
->execute();
|
||||||
|
$files = mpull($files, null, 'getPHID');
|
||||||
|
} else {
|
||||||
|
$files = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($repositories as $repository) {
|
||||||
|
$file = idx($files, $repository->getProfileImagePHID());
|
||||||
|
if (!$file) {
|
||||||
|
if (!$default) {
|
||||||
|
$default = PhabricatorFile::loadBuiltin(
|
||||||
|
$this->getViewer(),
|
||||||
|
'repo/code.png');
|
||||||
|
}
|
||||||
|
$file = $default;
|
||||||
|
}
|
||||||
|
$repository->attachProfileImageFile($file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return $repositories;
|
return $repositories;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,8 @@ final class PhabricatorRepositorySearchEngine
|
||||||
return id(new PhabricatorRepositoryQuery())
|
return id(new PhabricatorRepositoryQuery())
|
||||||
->needProjectPHIDs(true)
|
->needProjectPHIDs(true)
|
||||||
->needCommitCounts(true)
|
->needCommitCounts(true)
|
||||||
->needMostRecentCommits(true);
|
->needMostRecentCommits(true)
|
||||||
|
->needProfileImage(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function buildCustomSearchFields() {
|
protected function buildCustomSearchFields() {
|
||||||
|
@ -165,7 +166,8 @@ final class PhabricatorRepositorySearchEngine
|
||||||
->setObject($repository)
|
->setObject($repository)
|
||||||
->setHeader($repository->getName())
|
->setHeader($repository->getName())
|
||||||
->setObjectName($repository->getMonogram())
|
->setObjectName($repository->getMonogram())
|
||||||
->setHref($repository->getURI());
|
->setHref($repository->getURI())
|
||||||
|
->setImageURI($repository->getProfileImageURI());
|
||||||
|
|
||||||
$commit = $repository->getMostRecentCommit();
|
$commit = $repository->getMostRecentCommit();
|
||||||
if ($commit) {
|
if ($commit) {
|
||||||
|
|
|
@ -57,6 +57,7 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
|
||||||
protected $viewPolicy;
|
protected $viewPolicy;
|
||||||
protected $editPolicy;
|
protected $editPolicy;
|
||||||
protected $pushPolicy;
|
protected $pushPolicy;
|
||||||
|
protected $profileImagePHID;
|
||||||
|
|
||||||
protected $versionControlSystem;
|
protected $versionControlSystem;
|
||||||
protected $details = array();
|
protected $details = array();
|
||||||
|
@ -69,6 +70,7 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
|
||||||
private $mostRecentCommit = self::ATTACHABLE;
|
private $mostRecentCommit = self::ATTACHABLE;
|
||||||
private $projectPHIDs = self::ATTACHABLE;
|
private $projectPHIDs = self::ATTACHABLE;
|
||||||
private $uris = self::ATTACHABLE;
|
private $uris = self::ATTACHABLE;
|
||||||
|
private $profileImageFile = self::ATTACHABLE;
|
||||||
|
|
||||||
|
|
||||||
public static function initializeNewRepository(PhabricatorUser $actor) {
|
public static function initializeNewRepository(PhabricatorUser $actor) {
|
||||||
|
@ -110,6 +112,7 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
|
||||||
'credentialPHID' => 'phid?',
|
'credentialPHID' => 'phid?',
|
||||||
'almanacServicePHID' => 'phid?',
|
'almanacServicePHID' => 'phid?',
|
||||||
'localPath' => 'text128?',
|
'localPath' => 'text128?',
|
||||||
|
'profileImagePHID' => 'phid?',
|
||||||
),
|
),
|
||||||
self::CONFIG_KEY_SCHEMA => array(
|
self::CONFIG_KEY_SCHEMA => array(
|
||||||
'callsign' => array(
|
'callsign' => array(
|
||||||
|
@ -478,6 +481,20 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getProfileImageURI() {
|
||||||
|
return $this->getProfileImageFile()->getBestURI();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function attachProfileImageFile(PhabricatorFile $file) {
|
||||||
|
$this->profileImageFile = $file;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getProfileImageFile() {
|
||||||
|
return $this->assertAttached($this->profileImageFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* -( Remote Command Execution )------------------------------------------- */
|
/* -( Remote Command Execution )------------------------------------------- */
|
||||||
|
|
||||||
|
@ -682,6 +699,7 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
|
||||||
$action = idx($params, 'action');
|
$action = idx($params, 'action');
|
||||||
switch ($action) {
|
switch ($action) {
|
||||||
case 'history':
|
case 'history':
|
||||||
|
case 'graph':
|
||||||
case 'browse':
|
case 'browse':
|
||||||
case 'change':
|
case 'change':
|
||||||
case 'lastmodified':
|
case 'lastmodified':
|
||||||
|
@ -759,6 +777,7 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
|
||||||
switch ($action) {
|
switch ($action) {
|
||||||
case 'change':
|
case 'change':
|
||||||
case 'history':
|
case 'history':
|
||||||
|
case 'graph':
|
||||||
case 'browse':
|
case 'browse':
|
||||||
case 'lastmodified':
|
case 'lastmodified':
|
||||||
case 'tags':
|
case 'tags':
|
||||||
|
|
|
@ -238,7 +238,14 @@ abstract class PhabricatorProfileMenuEngine extends Phobject {
|
||||||
case 'view':
|
case 'view':
|
||||||
$navigation->selectFilter($selected_item->getDefaultMenuItemKey());
|
$navigation->selectFilter($selected_item->getDefaultMenuItemKey());
|
||||||
|
|
||||||
|
try {
|
||||||
$content = $this->buildItemViewContent($selected_item);
|
$content = $this->buildItemViewContent($selected_item);
|
||||||
|
} catch (Exception $ex) {
|
||||||
|
$content = id(new PHUIInfoView())
|
||||||
|
->setTitle(pht('Unable to Render Dashboard'))
|
||||||
|
->setErrors(array($ex->getMessage()));
|
||||||
|
}
|
||||||
|
|
||||||
$crumbs->addTextCrumb($selected_item->getDisplayName());
|
$crumbs->addTextCrumb($selected_item->getDisplayName());
|
||||||
if (!$content) {
|
if (!$content) {
|
||||||
return new Aphront404Response();
|
return new Aphront404Response();
|
||||||
|
|
|
@ -18,6 +18,14 @@ final class PhabricatorSearchCheckboxesField
|
||||||
return array();
|
return array();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function didReadValueFromSavedQuery($value) {
|
||||||
|
if (!is_array($value)) {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
protected function getValueFromRequest(AphrontRequest $request, $key) {
|
protected function getValueFromRequest(AphrontRequest $request, $key) {
|
||||||
return $this->getListFromRequest($request, $key);
|
return $this->getListFromRequest($request, $key);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ final class PhabricatorSelectEditField
|
||||||
extends PhabricatorEditField {
|
extends PhabricatorEditField {
|
||||||
|
|
||||||
private $options;
|
private $options;
|
||||||
|
private $optionAliases = array();
|
||||||
|
|
||||||
public function setOptions(array $options) {
|
public function setOptions(array $options) {
|
||||||
$this->options = $options;
|
$this->options = $options;
|
||||||
|
@ -17,6 +18,24 @@ final class PhabricatorSelectEditField
|
||||||
return $this->options;
|
return $this->options;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setOptionAliases(array $option_aliases) {
|
||||||
|
$this->optionAliases = $option_aliases;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getOptionAliases() {
|
||||||
|
return $this->optionAliases;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getDefaultValueFromConfiguration($value) {
|
||||||
|
return $this->getCanonicalValue($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getValueForControl() {
|
||||||
|
$value = parent::getValueForControl();
|
||||||
|
return $this->getCanonicalValue($value);
|
||||||
|
}
|
||||||
|
|
||||||
protected function newControl() {
|
protected function newControl() {
|
||||||
return id(new AphrontFormSelectControl())
|
return id(new AphrontFormSelectControl())
|
||||||
->setOptions($this->getOptions());
|
->setOptions($this->getOptions());
|
||||||
|
@ -35,4 +54,16 @@ final class PhabricatorSelectEditField
|
||||||
return new ConduitStringParameterType();
|
return new ConduitStringParameterType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getCanonicalValue($value) {
|
||||||
|
$options = $this->getOptions();
|
||||||
|
if (!isset($options[$value])) {
|
||||||
|
$aliases = $this->getOptionAliases();
|
||||||
|
if (isset($aliases[$value])) {
|
||||||
|
$value = $aliases[$value];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -159,7 +159,8 @@ final class PHUIIconExample extends PhabricatorUIExample {
|
||||||
->setIcon($icon)
|
->setIcon($icon)
|
||||||
->setBackground('bg-blue')
|
->setBackground('bg-blue')
|
||||||
->setHref('#')
|
->setHref('#')
|
||||||
->addClass('mmr');
|
->addClass('mmr')
|
||||||
|
->setTooltip($icon);
|
||||||
}
|
}
|
||||||
|
|
||||||
$layout_cicons = id(new PHUIBoxView())
|
$layout_cicons = id(new PHUIBoxView())
|
||||||
|
|
|
@ -11,24 +11,24 @@ final class PhabricatorClusterExceptionHandler
|
||||||
return pht('Handles runtime problems with cluster configuration.');
|
return pht('Handles runtime problems with cluster configuration.');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function canHandleRequestException(
|
public function canHandleRequestThrowable(
|
||||||
AphrontRequest $request,
|
AphrontRequest $request,
|
||||||
Exception $ex) {
|
$throwable) {
|
||||||
return ($ex instanceof PhabricatorClusterException);
|
return ($throwable instanceof PhabricatorClusterException);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handleRequestException(
|
public function handleRequestThrowable(
|
||||||
AphrontRequest $request,
|
AphrontRequest $request,
|
||||||
Exception $ex) {
|
$throwable) {
|
||||||
|
|
||||||
$viewer = $this->getViewer($request);
|
$viewer = $this->getViewer($request);
|
||||||
|
|
||||||
$title = $ex->getExceptionTitle();
|
$title = $throwable->getExceptionTitle();
|
||||||
|
|
||||||
$dialog = id(new AphrontDialogView())
|
$dialog = id(new AphrontDialogView())
|
||||||
->setTitle($title)
|
->setTitle($title)
|
||||||
->setUser($viewer)
|
->setUser($viewer)
|
||||||
->appendParagraph($ex->getMessage())
|
->appendParagraph($throwable->getMessage())
|
||||||
->addCancelButton('/', pht('Proceed With Caution'));
|
->addCancelButton('/', pht('Proceed With Caution'));
|
||||||
|
|
||||||
return id(new AphrontDialogResponse())
|
return id(new AphrontDialogResponse())
|
||||||
|
|
|
@ -60,4 +60,7 @@ interface PhabricatorInlineCommentInterface extends PhabricatorMarkupInterface {
|
||||||
public function supportsHiding();
|
public function supportsHiding();
|
||||||
public function isHidden();
|
public function isHidden();
|
||||||
|
|
||||||
|
public function getDateModified();
|
||||||
|
public function getDateCreated();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,6 +107,14 @@ final class PHUIDiffInlineCommentDetailView
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$is_draft_done = false;
|
||||||
|
switch ($inline->getFixedState()) {
|
||||||
|
case PhabricatorInlineCommentInterface::STATE_DRAFT:
|
||||||
|
case PhabricatorInlineCommentInterface::STATE_UNDRAFT:
|
||||||
|
$is_draft_done = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
$is_synthetic = false;
|
$is_synthetic = false;
|
||||||
if ($inline->getSyntheticAuthor()) {
|
if ($inline->getSyntheticAuthor()) {
|
||||||
$is_synthetic = true;
|
$is_synthetic = true;
|
||||||
|
@ -126,6 +134,7 @@ final class PHUIDiffInlineCommentDetailView
|
||||||
'isFixed' => $is_fixed,
|
'isFixed' => $is_fixed,
|
||||||
'isGhost' => $inline->getIsGhost(),
|
'isGhost' => $inline->getIsGhost(),
|
||||||
'isSynthetic' => $is_synthetic,
|
'isSynthetic' => $is_synthetic,
|
||||||
|
'isDraftDone' => $is_draft_done,
|
||||||
);
|
);
|
||||||
|
|
||||||
$sigil = 'differential-inline-comment';
|
$sigil = 'differential-inline-comment';
|
||||||
|
@ -265,7 +274,7 @@ final class PHUIDiffInlineCommentDetailView
|
||||||
if (!$this->preview && $this->canHide()) {
|
if (!$this->preview && $this->canHide()) {
|
||||||
$action_buttons[] = id(new PHUIButtonView())
|
$action_buttons[] = id(new PHUIButtonView())
|
||||||
->setTag('a')
|
->setTag('a')
|
||||||
->setTooltip(pht('Hide Comment'))
|
->setTooltip(pht('Collapse'))
|
||||||
->setIcon('fa-times')
|
->setIcon('fa-times')
|
||||||
->addSigil('hide-inline')
|
->addSigil('hide-inline')
|
||||||
->setMustCapture(true);
|
->setMustCapture(true);
|
||||||
|
|
|
@ -121,14 +121,13 @@ final class PHUIDiffInlineCommentEditView
|
||||||
private function renderBody() {
|
private function renderBody() {
|
||||||
$buttons = array();
|
$buttons = array();
|
||||||
|
|
||||||
$buttons[] = phutil_tag('button', array(), pht('Save Draft'));
|
$buttons[] = id(new PHUIButtonView())
|
||||||
$buttons[] = javelin_tag(
|
->setText(pht('Save Draft'));
|
||||||
'button',
|
|
||||||
array(
|
$buttons[] = id(new PHUIButtonView())
|
||||||
'sigil' => 'inline-edit-cancel',
|
->setText(pht('Cancel'))
|
||||||
'class' => 'grey',
|
->setColor(PHUIButtonView::GREY)
|
||||||
),
|
->addSigil('inline-edit-cancel');
|
||||||
pht('Cancel'));
|
|
||||||
|
|
||||||
$title = phutil_tag(
|
$title = phutil_tag(
|
||||||
'div',
|
'div',
|
||||||
|
|
66
src/infrastructure/diff/view/PHUIDiffInlineThreader.php
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PHUIDiffInlineThreader extends Phobject {
|
||||||
|
|
||||||
|
public function reorderAndThreadCommments(array $comments) {
|
||||||
|
$comments = msort($comments, 'getID');
|
||||||
|
|
||||||
|
// Build an empty map of all the comments we actually have. If a comment
|
||||||
|
// is a reply but the parent has gone missing, we don't want it to vanish
|
||||||
|
// completely.
|
||||||
|
$comment_phids = mpull($comments, 'getPHID');
|
||||||
|
$replies = array_fill_keys($comment_phids, array());
|
||||||
|
|
||||||
|
// Now, remove all comments which are replies, leaving only the top-level
|
||||||
|
// comments.
|
||||||
|
foreach ($comments as $key => $comment) {
|
||||||
|
$reply_phid = $comment->getReplyToCommentPHID();
|
||||||
|
if (isset($replies[$reply_phid])) {
|
||||||
|
$replies[$reply_phid][] = $comment;
|
||||||
|
unset($comments[$key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// For each top level comment, add the comment, then add any replies
|
||||||
|
// to it. Do this recursively so threads are shown in threaded order.
|
||||||
|
$results = array();
|
||||||
|
foreach ($comments as $comment) {
|
||||||
|
$results[] = $comment;
|
||||||
|
$phid = $comment->getPHID();
|
||||||
|
$descendants = $this->getInlineReplies($replies, $phid, 1);
|
||||||
|
foreach ($descendants as $descendant) {
|
||||||
|
$results[] = $descendant;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we have anything left, they were cyclic references. Just dump
|
||||||
|
// them in a the end. This should be impossible, but users are very
|
||||||
|
// creative.
|
||||||
|
foreach ($replies as $phid => $comments) {
|
||||||
|
foreach ($comments as $comment) {
|
||||||
|
$results[] = $comment;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $results;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getInlineReplies(array &$replies, $phid, $depth) {
|
||||||
|
$comments = idx($replies, $phid, array());
|
||||||
|
unset($replies[$phid]);
|
||||||
|
|
||||||
|
$results = array();
|
||||||
|
foreach ($comments as $comment) {
|
||||||
|
$results[] = $comment;
|
||||||
|
$descendants = $this->getInlineReplies(
|
||||||
|
$replies,
|
||||||
|
$comment->getPHID(),
|
||||||
|
$depth + 1);
|
||||||
|
foreach ($descendants as $descendant) {
|
||||||
|
$results[] = $descendant;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $results;
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,7 +8,7 @@ final class PHUIDiffRevealIconView extends AphrontView {
|
||||||
->addSigil('has-tooltip')
|
->addSigil('has-tooltip')
|
||||||
->setMetadata(
|
->setMetadata(
|
||||||
array(
|
array(
|
||||||
'tip' => pht('Show Hidden Comment'),
|
'tip' => pht('Expand'),
|
||||||
'align' => 'E',
|
'align' => 'E',
|
||||||
'size' => 275,
|
'size' => 275,
|
||||||
));
|
));
|
||||||
|
|
|
@ -2,34 +2,37 @@
|
||||||
|
|
||||||
final class PhabricatorYoutubeRemarkupRule extends PhutilRemarkupRule {
|
final class PhabricatorYoutubeRemarkupRule extends PhutilRemarkupRule {
|
||||||
|
|
||||||
private $uri;
|
|
||||||
|
|
||||||
public function getPriority() {
|
public function getPriority() {
|
||||||
return 350.0;
|
return 350.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function apply($text) {
|
public function apply($text) {
|
||||||
$this->uri = new PhutilURI($text);
|
try {
|
||||||
|
$uri = new PhutilURI($text);
|
||||||
if ($this->uri->getDomain() &&
|
} catch (Exception $ex) {
|
||||||
preg_match('/(^|\.)youtube\.com$/', $this->uri->getDomain()) &&
|
return $text;
|
||||||
idx($this->uri->getQueryParams(), 'v')) {
|
}
|
||||||
return $this->markupYoutubeLink();
|
|
||||||
}
|
$domain = $uri->getDomain();
|
||||||
|
if (!preg_match('/(^|\.)youtube\.com\z/', $domain)) {
|
||||||
|
return $text;
|
||||||
|
}
|
||||||
|
|
||||||
|
$params = $uri->getQueryParams();
|
||||||
|
$v_param = idx($params, 'v');
|
||||||
|
if (!strlen($v_param)) {
|
||||||
return $text;
|
return $text;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function markupYoutubeLink() {
|
|
||||||
$v = idx($this->uri->getQueryParams(), 'v');
|
|
||||||
$text_mode = $this->getEngine()->isTextMode();
|
$text_mode = $this->getEngine()->isTextMode();
|
||||||
$mail_mode = $this->getEngine()->isHTMLMailMode();
|
$mail_mode = $this->getEngine()->isHTMLMailMode();
|
||||||
|
|
||||||
if ($text_mode || $mail_mode) {
|
if ($text_mode || $mail_mode) {
|
||||||
return $this->getEngine()->storeText('http://youtu.be/'.$v);
|
return $text;
|
||||||
}
|
}
|
||||||
|
|
||||||
$youtube_src = 'https://www.youtube.com/embed/'.$v;
|
$youtube_src = 'https://www.youtube.com/embed/'.$v_param;
|
||||||
|
|
||||||
$iframe = $this->newTag(
|
$iframe = $this->newTag(
|
||||||
'div',
|
'div',
|
||||||
array(
|
array(
|
||||||
|
@ -45,6 +48,7 @@ final class PhabricatorYoutubeRemarkupRule extends PhutilRemarkupRule {
|
||||||
'frameborder' => 0,
|
'frameborder' => 0,
|
||||||
),
|
),
|
||||||
''));
|
''));
|
||||||
|
|
||||||
return $this->getEngine()->storeText($iframe);
|
return $this->getEngine()->storeText($iframe);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@ final class PHUIIconView extends AphrontTagView {
|
||||||
private $iconFont;
|
private $iconFont;
|
||||||
private $iconColor;
|
private $iconColor;
|
||||||
private $iconBackground;
|
private $iconBackground;
|
||||||
|
private $tooltip;
|
||||||
|
|
||||||
public function setHref($href) {
|
public function setHref($href) {
|
||||||
$this->href = $href;
|
$this->href = $href;
|
||||||
|
@ -60,6 +61,11 @@ final class PHUIIconView extends AphrontTagView {
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setTooltip($text) {
|
||||||
|
$this->tooltip = $text;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
protected function getTagName() {
|
protected function getTagName() {
|
||||||
$tag = 'span';
|
$tag = 'span';
|
||||||
if ($this->href) {
|
if ($this->href) {
|
||||||
|
@ -100,11 +106,24 @@ final class PHUIIconView extends AphrontTagView {
|
||||||
$this->appendChild($this->text);
|
$this->appendChild($this->text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$sigil = null;
|
||||||
|
$meta = array();
|
||||||
|
if ($this->tooltip) {
|
||||||
|
Javelin::initBehavior('phabricator-tooltips');
|
||||||
|
require_celerity_resource('aphront-tooltip-css');
|
||||||
|
$sigil = 'has-tooltip';
|
||||||
|
$meta = array(
|
||||||
|
'tip' => $this->tooltip,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return array(
|
return array(
|
||||||
'href' => $this->href,
|
'href' => $this->href,
|
||||||
'style' => $style,
|
'style' => $style,
|
||||||
'aural' => false,
|
'aural' => false,
|
||||||
'class' => $classes,
|
'class' => $classes,
|
||||||
|
'sigil' => $sigil,
|
||||||
|
'meta' => $meta,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ final class PHUITwoColumnView extends AphrontTagView {
|
||||||
private $header;
|
private $header;
|
||||||
private $subheader;
|
private $subheader;
|
||||||
private $footer;
|
private $footer;
|
||||||
|
private $tabs;
|
||||||
private $propertySection = array();
|
private $propertySection = array();
|
||||||
private $curtain;
|
private $curtain;
|
||||||
|
|
||||||
|
@ -42,6 +43,12 @@ final class PHUITwoColumnView extends AphrontTagView {
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setTabs(PHUIListView $tabs) {
|
||||||
|
$tabs->setType(PHUIListView::TABBAR_LIST);
|
||||||
|
$this->tabs = $tabs;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
public function setFooter($footer) {
|
public function setFooter($footer) {
|
||||||
$this->footer = $footer;
|
$this->footer = $footer;
|
||||||
return $this;
|
return $this;
|
||||||
|
@ -91,6 +98,10 @@ final class PHUITwoColumnView extends AphrontTagView {
|
||||||
$classes[] = 'phui-two-column-fluid';
|
$classes[] = 'phui-two-column-fluid';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($this->tabs) {
|
||||||
|
$classes[] = 'with-tabs';
|
||||||
|
}
|
||||||
|
|
||||||
if ($this->subheader) {
|
if ($this->subheader) {
|
||||||
$classes[] = 'with-subheader';
|
$classes[] = 'with-subheader';
|
||||||
}
|
}
|
||||||
|
@ -124,6 +135,12 @@ final class PHUITwoColumnView extends AphrontTagView {
|
||||||
'phui-two-column-header', $this->header);
|
'phui-two-column-header', $this->header);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$tabs = null;
|
||||||
|
if ($this->tabs) {
|
||||||
|
$tabs = phutil_tag_div(
|
||||||
|
'phui-two-column-tabs', $this->tabs);
|
||||||
|
}
|
||||||
|
|
||||||
$subheader = null;
|
$subheader = null;
|
||||||
if ($this->subheader) {
|
if ($this->subheader) {
|
||||||
$subheader = phutil_tag_div(
|
$subheader = phutil_tag_div(
|
||||||
|
@ -137,6 +154,7 @@ final class PHUITwoColumnView extends AphrontTagView {
|
||||||
),
|
),
|
||||||
array(
|
array(
|
||||||
$header,
|
$header,
|
||||||
|
$tabs,
|
||||||
$subheader,
|
$subheader,
|
||||||
$table,
|
$table,
|
||||||
$footer,
|
$footer,
|
||||||
|
|