From 0d1654446be6de43b2bd12fcc247db0dc1a46464 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Fri, 9 Jun 2017 22:17:36 +0000 Subject: [PATCH 01/34] Clean up spacing on diff-banner Summary: Adds spacing to the buttons, line-height for aligning text vertically. Test Plan: Leave comments on a diff. Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Differential Revision: https://secure.phabricator.com/D18110 --- resources/celerity/map.php | 12 ++++++------ .../css/application/differential/changeset-view.css | 9 +++++++-- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/resources/celerity/map.php b/resources/celerity/map.php index 1c0fb7fb3c..2209dffea7 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -12,7 +12,7 @@ return array( 'core.pkg.css' => 'ab24402f', 'core.pkg.js' => '1475bd91', 'darkconsole.pkg.js' => '1f9a31bc', - 'differential.pkg.css' => '1ccbf3a9', + 'differential.pkg.css' => '4e99863c', 'differential.pkg.js' => 'b7504037', 'diffusion.pkg.css' => 'b93d9b8c', 'diffusion.pkg.js' => '6134c5a1', @@ -64,7 +64,7 @@ return array( 'rsrc/css/application/dashboard/dashboard.css' => 'fe5b1869', 'rsrc/css/application/diff/inline-comment-summary.css' => '51efda3a', 'rsrc/css/application/differential/add-comment.css' => 'c47f8c40', - 'rsrc/css/application/differential/changeset-view.css' => 'c3f44655', + 'rsrc/css/application/differential/changeset-view.css' => 'c72dba88', 'rsrc/css/application/differential/core.css' => '5b7b8ff4', 'rsrc/css/application/differential/phui-inline-comment.css' => 'ffd1a542', 'rsrc/css/application/differential/revision-comment.css' => '14b8565a', @@ -562,7 +562,7 @@ return array( 'conpherence-thread-manager' => '4d863052', 'conpherence-transaction-css' => '85129c68', 'd3' => 'a11a5ff2', - 'differential-changeset-view-css' => 'c3f44655', + 'differential-changeset-view-css' => 'c72dba88', 'differential-core-view-css' => '5b7b8ff4', 'differential-revision-add-comment-css' => 'c47f8c40', 'differential-revision-comment-css' => '14b8565a', @@ -1872,9 +1872,6 @@ return array( 'javelin-dom', 'javelin-vector', ), - 'c3f44655' => array( - 'phui-inline-comment-view-css', - ), 'c420b0b9' => array( 'javelin-behavior', 'javelin-behavior-device', @@ -1896,6 +1893,9 @@ return array( 'javelin-stratcom', 'javelin-util', ), + 'c72dba88' => array( + 'phui-inline-comment-view-css', + ), 'c7ccd872' => array( 'phui-fontkit-css', ), diff --git a/webroot/rsrc/css/application/differential/changeset-view.css b/webroot/rsrc/css/application/differential/changeset-view.css index 33dcea1213..bfde532c44 100644 --- a/webroot/rsrc/css/application/differential/changeset-view.css +++ b/webroot/rsrc/css/application/differential/changeset-view.css @@ -392,13 +392,14 @@ tr.differential-inline-loading { top: 0; left: 0; right: 0; - background: rgba(255, 255, 255, 0.95); + background: #fff; box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.1); border-bottom: 1px solid {$lightgreyborder}; - padding: 12px 18px; + padding: 8px 18px; vertical-align: middle; font-weight: bold; font-size: {$biggerfontsize}; + line-height: 28px; } .diff-banner .phui-icon-view { @@ -409,6 +410,10 @@ tr.differential-inline-loading { color: {$greytext}; } +.diff-banner-buttons .button { + margin-left: 8px; +} + .diff-banner-has-unsaved, .diff-banner-has-unsubmitted { background: {$sh-yellowbackground}; From 83a89166ee339758c556ef41fd6fe20c5e3da747 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Mon, 12 Jun 2017 07:51:16 -0700 Subject: [PATCH 02/34] Add profile images to Repositories Summary: Builds out some images to use to identify repositories. Fixes T12825. Test Plan: Try setting custom, built in, and null images. {F4998175} {F4998192} Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Maniphest Tasks: T12825 Differential Revision: https://secure.phabricator.com/D18116 --- externals/octicons/LICENSE | 21 ++ externals/octicons/README.md | 194 ++++++++++++++ resources/builtin/repo/building.png | Bin 0 -> 1538 bytes resources/builtin/repo/cloud.png | Bin 0 -> 2821 bytes resources/builtin/repo/code.png | Bin 0 -> 4346 bytes resources/builtin/repo/commit.png | Bin 0 -> 3028 bytes resources/builtin/repo/database.png | Bin 0 -> 4716 bytes resources/builtin/repo/desktop.png | Bin 0 -> 1688 bytes resources/builtin/repo/gears.png | Bin 0 -> 5903 bytes resources/builtin/repo/globe.png | Bin 0 -> 5820 bytes resources/builtin/repo/locked.png | Bin 0 -> 2888 bytes resources/builtin/repo/microchip.png | Bin 0 -> 2456 bytes resources/builtin/repo/mobile.png | Bin 0 -> 1905 bytes resources/builtin/repo/repo.png | Bin 0 -> 1950 bytes resources/builtin/repo/servers.png | Bin 0 -> 1800 bytes .../20170612.repository.image.01.sql | 2 + src/__phutil_library_map__.php | 2 + .../PhabricatorDiffusionApplication.php | 2 + .../DiffusionRepositoryController.php | 4 +- ...sionRepositoryProfilePictureController.php | 246 ++++++++++++++++++ .../diffusion/request/DiffusionRequest.php | 1 + .../query/PhabricatorRepositoryQuery.php | 36 +++ .../PhabricatorRepositorySearchEngine.php | 6 +- .../storage/PhabricatorRepository.php | 17 ++ 24 files changed, 528 insertions(+), 3 deletions(-) create mode 100644 externals/octicons/LICENSE create mode 100644 externals/octicons/README.md create mode 100644 resources/builtin/repo/building.png create mode 100644 resources/builtin/repo/cloud.png create mode 100644 resources/builtin/repo/code.png create mode 100644 resources/builtin/repo/commit.png create mode 100644 resources/builtin/repo/database.png create mode 100644 resources/builtin/repo/desktop.png create mode 100644 resources/builtin/repo/gears.png create mode 100644 resources/builtin/repo/globe.png create mode 100644 resources/builtin/repo/locked.png create mode 100644 resources/builtin/repo/microchip.png create mode 100644 resources/builtin/repo/mobile.png create mode 100644 resources/builtin/repo/repo.png create mode 100644 resources/builtin/repo/servers.png create mode 100644 resources/sql/autopatches/20170612.repository.image.01.sql create mode 100644 src/applications/diffusion/controller/DiffusionRepositoryProfilePictureController.php diff --git a/externals/octicons/LICENSE b/externals/octicons/LICENSE new file mode 100644 index 0000000000..4cf2020ce7 --- /dev/null +++ b/externals/octicons/LICENSE @@ -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. diff --git a/externals/octicons/README.md b/externals/octicons/README.md new file mode 100644 index 0000000000..84edd84dce --- /dev/null +++ b/externals/octicons/README.md @@ -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: '', +// 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 +// +``` + +#### `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() +// +``` + +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 `` tag. + +```js +octicons.x.toSVG({ "class": "close" }) +// +``` + +##### aria-label + +Add accessibility `aria-label` to the icon. + +```js +octicons.x.toSVG({ "aria-label": "Close the window" }) +// +``` + +##### width & height + +Size the SVG icon larger using `width` & `height` independently or together. + +```js +octicons.x.toSVG({ "width": 45 }) +// +``` + +#### `octicons.alert.toSVGUse()` + +Returns a string of the svg tag with the `` tag, for use with the spritesheet located in the /build/ directory. + +```js +octicons.x.toSVGUse() +// +``` + +### 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 ` 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 diff --git a/resources/builtin/repo/building.png b/resources/builtin/repo/building.png new file mode 100644 index 0000000000000000000000000000000000000000..dd39fb8f140f158dc8676adebb509e0771069baa GIT binary patch literal 1538 zcmeAS@N?(olHy`uVBq!ia0y~yVAKI&4rZW;-{LxVAV(pc#T@@PYLE#mW->l;=XhIZt`MUp>)S4AaHG%f2fPF*n`d< z5w4GY?>Rf_gr2xQa{TJEMQ6h%O(TQq(#ra0hT6s&-h$otbPJkW{aAL&^uJb4T(4() zLh97@)5dKK3@nD8E{-7;jBoE;Ez@=vaC>OAz$!t;7zA!7`rZ4ld5CT2G3~eKvUE$c z-@o4VYu%ff^(rn15MsBt^7p%1$Ki9%fW|<$V68A-9IL*hFcWXYrSlPcs~S zy1!{Ctx+vD(OH&Syya2R7L{e8)gpq^X0;tLS)z7+ah&PV?y2=A3xLdhUI&@Dfi3_O zS!V9ddi7rGD&^MRUfi+4EM{NJ9TWFxJ@?y5w>G*9Ccb^O`IwPmsm{yI-(vd8j!x;F z2~?F5-#tri>YOaQj6ilh_x4GbUu?1L;_xmrpY?U$(pJrrxvySCywAR8QTZ?<@#V>j z>z)gqe^8moh!GHwz%e|K+HjhoJg#V#0dq|I;+K0CR~AqC$54L1c1+t64r-9S~?d;xYRNb39pq&PuyZx?rVdG%SlX8!9}maFc~&#gAs zTjTt>Ox>Y#&)u6>(|c2e41V7$Fn?u!saI%&?C(75wQHN}SLVvj>HFhdU&I0nbxZbZ z6Ij-S`>w3be-R&bU)rkn|uy3;J51xOk*MGelIzQ|McX!>_6&oTZM%-T!em_hlY3NfXtyJ~?KUzy)`BtZwgK~Ag`|}_-K?Jxc Zzqw3tgRE1!2C$%F@O1TaS?83{1OV)qoLm3^ literal 0 HcmV?d00001 diff --git a/resources/builtin/repo/cloud.png b/resources/builtin/repo/cloud.png new file mode 100644 index 0000000000000000000000000000000000000000..7c355b0adc84896144f15afcc0c1fd8f8a346122 GIT binary patch literal 2821 zcmeHI`#Td18=kW;<}eg0iL#J#OtFa(F`M%t=OmkBlZ_I!oKJZpL#Z}n@j4~sFsHq# zo_w(G>oq|MI0!5C90001>)fIDl0Dwp1 zcMJ0!Y!KvomH+_n0@B72en2tUjDPX30{_PfNG~{?J$Q6Zq&>m`z<)>#BmnE*ieB^X;I$ai?8NRu7`}HyErH@&P2^@xT{@%JL zZ&}p+riUp(*~n$*v&DCF1t}|+o!TTLRZc6%m|)(09v?_T8xVj2>Gj{sy>#2PN+w?j zZ%P$?oqlwO&+*5J!s9LMbLN)6rtU5FwRRbq(qCcEL_D!Y5t;k0HrxJbO0kLB7B_+s zW~mh#&=6Jq>bx*-I}cyKKjYqNK2W=8PtN>%=zRgS(R>#G5FE2IH+97GtaR7$@R|Yu z)eSmN>9Jh(Y}x$yVg%ir_dun8D!!hb1oBH)1~#U5K~)|v2e-P841bELom`c8zpa8o zEXFiW9i3+o{3usJ{4?%MeMtRieF*b6{4X}%qhc@w9plnP?$is^FwN3#-wNh~48L;I z70(|D0v!e`Nh`?pb8{XM8RfWRc(2~py&VbRnMI(YF8;%SV8)CaJuyrE0;CA6uN|>T z+}S7|_fJaqr(|&a?r-I5XFKTx{XpWaSJfTdZX1`_CgFOBA6bVA^c1GF1GUP-rtac9 zmIO9a63k|s;AzWeOs~$=QwYmupPtY?>s$sJ)H34BohwOI8SX#>y)-gU#Ynp`aI}&v z$u?-$1L}v8lnWbz6CBWCWK-s|ap%btU9`}|VBjerQ@}-c4L%n|2hwF7U|2(60r<*& zzHR%il2~Mw4rRrge?c7C_rV>x>Vp$8;_pST6jSK~7`9}$HIb+8MhK~Tpa6-sjZ4Ka zg&|7D7SZqRV3fyiW*I@JBV)i7hJ?7ft;oN=U>5@o61|&X7u6~{rgh)qUrnwpdF54I zqv=-#6tbCN6T$r4TT$AYjS0}^*u^#4?yvGaiO!>;30!JKUi}I*Y1-I*kH}r~VxHQN zGqW5l7`BY_7#=d;ZwTz)yY6|`d8jC_O=EVLZSX5DY+5Pdn0#%fER748@fU+uv8`M= zzPcehIq6Jwj+-Qh(^=nI801vTKsr0RdynZok5aM=eCPQo-qx}i`FJhAdTGU|?A9gG z?TPLZtqWKmTO3;YlERbX&=Mn>Nqgo5o`sc*+AOt@^EI1SK>~rUR4!hDME|AELfEbQBHyusK4e zP6P-?bJNEwc6m?q+4Yvhq*NV$(M5+D9hc!{#a+l0cQxSq2AsA!b!`tY*G*VT)YM-4 z%G)%{LJ_x}c$LoamBbo9$|N2dN;Mb)({AZN+lvYJBd@^9!;W?mlf#yY>oJsxhmzTz z%P%@;<8;muB~l@8Q}F$&jFMU}S=l{UpRwvvz5onRF;s>(-+Ywvotwa**lnWQ@?g)5f_XeseQ~ zNf}9RUN28K8?c@81IsM?_p12Xztu(lmM^*sSHC^eF`q>Z;G5XZ_Cq)lJfycBdb2-< zFGIG1Awn)vUC4pg+2JaQsU)e{&Z(2uJ0^$wdUuKnWS>0rSC;|jij+p_mXvu2%?z}J z=H&7xl_5ttDl-DSf;KdpXtFO_cY!A1;CXr-Vw3TrC6efF7d`A# z*28hk<8e@_LV2pCZ;_j{w4<_EnVn;QX2{?GU64r1+b!)pc*taT#{^9}CklJAC-!2( z=hw65ij-$b(m)eZHT8Qq>90AN`qJ}?ji$aA!oM-M8Fhl88949PoOnAZU(!(JvXb&`eFoHn@9Cy7G~^ChJz=>8$?V<#DefJ zwYoRsViJ`oYvq-b1tVff}-pX z--6i7RRol`&4y{wyhQ|XuN|`}1Y-E1wl}Ts>}m7tqkjs7)GbT?4CPym{I1I1zGU)d z;E&J3$#U!geN8M#JEAuz7mESG&Z-TbXf{%=HrXRSadl3QKLc%()!gWMPLUK_5Zym= z=RtPx+{eKHkOtUNvu!v{62f|^rVa)<=6;)gYNU}W8Tg&irf@>$h7%O`Eh$d^+|eCQ zo45+-^4ZqCi0K5|Y5YxLy6ejFD@^}LY8#SA+4%>P$EB#x@Zh3D`qLakse6JrXzdC& zkDMlvquwSbF;3u<`khRsT<-=IB+ow~^}lIGgAwiX!;JSQ=Qp*2Bg`u=`#ktB3Km2~ literal 0 HcmV?d00001 diff --git a/resources/builtin/repo/code.png b/resources/builtin/repo/code.png new file mode 100644 index 0000000000000000000000000000000000000000..f7e56be76276860087e987694d3397d22689ef74 GIT binary patch literal 4346 zcmeHKXHyf5(hVq8lq$UkLJK7iU3!(0&;>E*<-YgR{SEi-Y?-rPcIM3P%vp??$=#c@oU{M{;HII0t_1)<2L4x2U%Tp< zybZYv0FWP;L9O(zpeHKvfBruP{!19hdqt&iwe;t{7ABT}Cl$m-te;TY->DCIrj+`J z1Fey4J@fH&t0C7+4*sZ?K5&#+hbDkplE`k4z&+1T^4krMFYLm5Ul&2vULcmDYPm+U zjCZ_l)&F|D$ii;MdOiIcxz;^NkI&BgF&gipnPhiG%#R4nnaGXP{tPq;Z^iffuJxBo z8!BpB#vF{26o-YtbZ7*4SvOD&=ihf@>>)pexAxl~xehw+3xb+HoL?E9x^1a_GSJ(r zlMWu_{;vFNruk=f;pBFJ`h@Vu?pdCHD(!F9q@rGxZ9Z@7ET*M7OB7ddc_eBCe9udN zCuO|LRj#9YctyTE?!L^BN{M3f%Q={DRZ~M)K}?{n zqv#p?F`rJiI6BpwEg?}N24lzug-OJ4P}TOm9_Y+V$#Fzhi{di4!QdMux2eiJwGl77 zJBw4Mr~SVT)}>7QnR!uX_Y|NZ0`;MbZ@Pg3emjfK4hH#ml$b5n*=|WijisZvrSQn* zMQgFyIh6o2+T>dWInq0`E&;bEPAT^r^+xVt7LlCqaiPkujSg81d1#J#kFT$vUgzwb zqxaU5l9FVl&KYxf+N#L*ysV|=Ws}`NPHWIVwKjvep$ql55lqxLAcdc2|ek8fSMC|Ekmm z9dy={8g-yGsUVP=g{dA{)BmmyeRg)htH{xiSY|AYuaAlno9pe1B_T_mI`57+Ps*of zxoaWYHk~V+0F`4{D?~>zDUd*nj5-d-4a@9of%_b8W={i^CL6F>_T*-<_WHDyTa#c9BO@SNE>BV(B|duqgR-BeRoC=j>ujSjB&br? zuQq$Yp4oe^TX%$)63QP?BntN%lsL(M4D)uFd-P)Dy;`017v|;SKh{zutKAs+YsMPx zR?_iU66;50#|kuX8#7hS_@Z~%s!Y4LwSMcSs|ORxhN0ax@D0L?f-!g`0BR_gH{ z1KuuA9>ERA_71ft_$^(9+FhcYhK!rRd{Uv8{%bC9UN@@T7lbs6c4XkTfb7=+j98?X zF_WRYchdO~=$LoMn8-S*SX*w|JAF?OKNfu8!|4T!x%Sj$#yx3#D1?2L&j4zp#59qJ zZHQVyG-Qu`mhtpM!498W>SGX*8lJJXinl zZkD8;c5TN^sbL#kIXhCaF%d7%^nOp#)BH7srmM;5XvkZr2`P$={$&rM!$g#vp?&cZzf-0SQIha`Y41*MTQe zVWbRIcn|uieTI*CW|dqtvt=I5s6w&Zq4oVor#d|g7-hgw#zwJz7s&HOh;aQD6N;J~ z(Zkikgl?Wn4(^@mRs4oYTgqF!{&9aNre~a>8p$ac)@)a zi0%2g-IRjM2heL(%|Q;%(|ex6Ell`5#<$oaNFHZuNj-*eCQq#lZx7s-;KmNq!m=AU z$CxHG-vXRL4#v=v`{sQr?oSGya^8i3$C>DFzp!p*LVa}U~#y#YU4Wy`HB~6T# z(uA14XehRm6?l&jPai`$9ednUVWwlA);D^osAED7scJyu1b(Ji6y`5}TtVYl7U(Rr zEip~xuUOlPOU89|L1%szTmF>V^Xx{%T!y+*buqkJf&s<6Al_wwf7uIuN{Yyn{E;%! zqQcnZ3#+fGL`N>#!C7?%|AO2+PI!%g!DeYDxmudsKK7(ma(Kfr5MReEnjcY9NfIVl zWnC9@i4X&h!z56A8)n3K!pd_4%I@#Q3z2-2s<$u@$-^eM zS$9u>SPF%X5Ja87;h>XgZ@=1$brUoOK8-~+IlQfq%J+`e`ijDw0R&m+mxUTVg|?t{ZpBa z#^kICr&(snAP`kHAbwF=!O z!SII)56jMQR80Tlt@sMI;60xT&&qoo)NTZ3W*!+NaY|93d7AIJO(BH%vsjR zFf3DUC&rvGR!Nce#|GRu(|b6iR6^Q_$GG1|*w&r8rZA|B%2K5gV_Yq4I*Mvh_-8Hp zS`DCndbC3!{t*7TBTwKrid$^cQ{J>vYH8eR>(ZM z9*Reu=Zf01)yR+MU}Du^P}tIJ!7-@MZcu^Q5~zHHX`0il*h(9ThEgMkRbWrTdch{E z?TrO)^i2VR&Pp5og&!^j@DA}pt_^AbF!Cr<<(njOt7{VFlvs}5gW?OquEA~9@f_^M zQ)X=#Ug7K+5&jq2w^Rlk87$TAN;Qh8kp)^<0z2^pIacCsVJF!Vc)^4H_@A`c?9~Xc zI3l^yj$?Ssh?uE^s}cS2_2aG)IC9VzE^ahlI+Tk?f#74EwP4?rLxP z%3?VgMuUrqLCi060Nzy@ZPKBPS8D1Mb*@70`jDxsaWacj%*_yLJn2W$@_uffF*HqM z%$K-AA8A=F<{O3`DF_3+28Zs+ln3h(m&qoVLsPJEg<&(1wT2~Z;43{qRH=5Kmn2_T zijXQ7PB*Ep1{Kf`Sw+Dp9K}6PcpvEhtw?=yRK3p#>3`8#JlQ{Y$-P3$vU%*ur}Q@j zuJFrgf~Lmm0yHZ=Rb#i15FXWSiOIe;bCH}9braU{@lJk-S|S#N3gRC-c|pD4 zl`*n^?6(hR_q>-THeFjH%-&}j5WA6E*1v5FMa+03TZWURj;IJjd8kX-Hk`_sC_pZoVqGj)mb`?}MxCSL*7 zi~?Y>m}-Xq6OlE>0Pvg%G1_$TgIqyY|KbOhN^Pi=YKFoQ>=?$g^kFPJi#BHILyeml zsyjj}V@f%sdL|NK7%{+|?Ry+R$2Z-oCG6-=}8yKbBX2&d>6`4fXfb#;NTR zfcX?|{a%=!d>dqROxC+$?eC3&`wGft>GhY@_n`9Z;6(1P7?Xq-Zni5mfoF==A6KOw zlzBO5@Ygt{QAP2?(s^IY#emBF&A03PKpCe`Jm?;g*I;yg8kK6N=f^|Bli1jYPluH{ zkfqGsgiZb2*H^Y*c?q*R({jo~IVqUnNJFhl5qdTyc*)~Bb8Qu2ccOF=Z!)i!?Q1P~ zC)DC{n3ha-K9}|Jkkd_VXp^T0)g1i<{6*sZ#a)VxKL7yX*Jj2Bc0mGjU6F}@w!Zut z;VbjiZ&$tB51>b7u{+GaO*dvCd!*qvLJb^m?6GL9p7P1_*1BPZU6~!8q<4GeVpZ=v zF=VUBAC`r>w%qEjNNw= z@})bS3Ez8|JL#*=+THEUPtGCY-oMtd%~fjq)-@Q!rsmd`wclbTm-BJeGnzOd@0D@Y zm-a}$_V5q2*q9$&`jh8(y&F)y&)noyDfq$Xz8d9D%rM)HcZ17}ddGqCR9vMvSvd?>d%uZ)iC%O_%9llsnL z60%&Ka~y8)w||DoZLsBNwqD#4jK98f;co!V8FbwE63DO6szi3(w>qbe0fA?7@%g4D zqHc_qb{h!8{8C1oeR!KDnR)bBVNl7wzv3!lci~68O0@}~7T>9=#%JC@hwl2jO zsnU`z((O4*90OVsRIEf=62mMoq!)19my>?H(g4ymhl1eFNrV{4mpvG~ zEU~Grx6!=l6roPMUh8wWtj)ydlY6229*c(}{2HR}wrz)3heKCfign9*NKNrDZc{pj zL(jR1&mpVBio=)Ek%&k=sjW*#^>r;2h@9`h4cnv+3k^*qVtHT4Q!MBAN4;RYT>m`jl} zBp1=v+G+5s@ZFNV<7=}rq5h@N*0}uPA4em!cR+sJ za)T<~XuL>cdO{8%IuxQ{O}l-n^{z6U4?Mm$Lr zz2%A;cf4jKg9*h`JP7wZr(yA=J&&)P$t9Gs9AupG69?Mr(#0zI9JswAQlf-Vil>&{ z_OkGZx)M!nvV~DFD{2$RN_L)ZNT=INNLyyW}9V|RR(n8bBAr4Gj)u2wumP8>PV-F>CX>xUu zPtxn!1~veddOdJ%9hf?2;79OS6g`2jbQ*D_R2h`L?>T2bsYoq;?@HO>pAQ(*Jj9Lw zVxWAswzzGu%;%KOJMW=tAhstZH?P9yl^&I+tl}WLr+@WhJzhiUYLHxeWvXBn_Vuri z^-<-lH4^wB&}_i^oop>?lgSsN8Kww+^>`xWUNMZ|HtoxL#w$z+xVH^P|<>r^`zgt=l5i ziCkHw3ELyIp90Y7<)`~u*^=f?PEqlTQqk^YQh{w9LhJJsH6rO*rf=A^$c-CHQwefJ z!_&zO<;-6$=3@2 zz}AJZI;2cp_HBznrfxohEA=0A4ywpV-GJ<}7$lfH8Y(&vc4C!np50)eXferFPr12*W&ca5cRlQ|H)P?rjqlY)mR;3k}yOO^pL|a6RXr*{gi9^6Og>Jjn zisqBfEUeG)>*Mvs#OGDIr#yaLJ+S#yQH_(~Cj1#g4`3o+i)=q3bw*2^u~S=^w29hJGi{pV{$Mi`OXD)b Hs}cVIiSwi` literal 0 HcmV?d00001 diff --git a/resources/builtin/repo/database.png b/resources/builtin/repo/database.png new file mode 100644 index 0000000000000000000000000000000000000000..2132b8504126bdfd63592d76dce49b971b272d56 GIT binary patch literal 4716 zcmeHK=QkUU-wm2oFKW};O(|+rW7ep> zXBE%)_v-iN`467wbMEKGy)W-M_nvcOb+y%~D3~b#005ObLInu`5D5S0$$K5~teoT}~tY(aXA zi2x}gqVwCzpWjn`AYyLu&HbyJt))UM89K1>o95fGXbWx5=UHV@Z4*ULNzQ%^*-^h} zcqaBG#G`&UfrG4ck@lY3^vR={Q{QdoIePcwdV}7nIMp1<9z2Yb&4kJSfVL}L6F1VHP|*| z>IgGGFJZm9l;DavXMwK!`d*v|(llvHp*O`G`z7yUY6EX4rdTJ(8dh=4iYVw=(RXs*#muCEq^bsn;^i`T?8eAUhvB3o2G4SsBC9mq z{F3$D5*Cp@dWo%CgGcIJB_GnYh#?~(dg$toi(!Kc_F=8FLpsRr5q&nc%Urjffgm<8AnZYxDa$L>DR zvYpKVC#i`X3{b1-ydTKMV>C7p_x>!*r0rPGu12RnE`Hbq*pG8aZV2)p{QUK)aR2{` z&ms40&bVgkD4`bJG4IdPO|H)KJ3BmZoUYe0Xt1x)%8R13<`wnqtkV>miTH4>*+04@ zOleH~zM+wmBvf(nstA79iTW0I_Ny81J_X5Hsp~8Hjm@3Q;NML^64Wz`Y@+8H87hj& z#Bh|_13hsdT-A&tWWLB(_lqK*)jZJ}dDSZ`a}B}cr}K(d$~lzBN&zJGoZj+CQO$cM zHX-x^Z=8AS`G~4~%?N(1IYped6AI^gk_x0dQSN$6sZt22*#qy7VTPbD<*|&RLKA&F z$-L2Cp_=V&rl%o-=XTVoPbtbV6-OyWZCc{TWW$`>!X0$N-!;K`Bs~2Evv2PXOLu3A22&w**i%{ zHId>0&`@K*tAGi?>H(MLK_H&Uolo5#J`|=Rs{b;(cSV^Qs5czm>gQO|SmA38jVWI5 zg+7-f2}gdZ8)t3%N&&Im>aq!ZnIKB$w1Nl%fhgcXro_Q?+j5VNGmHEfFqKcS+lL&- z0ps^cPfYktSJ~2w63b_&x+i}e2K>`h;XlH<%M}NO;ebl>8}`j=kmHeXNtjny-Xg4`#w*2=fFemIqGay>L$gr5a|7CXdHx(9C7S0 zR_@6wv>ID1H!ysbrN*-BusK80y8V^1&Z5V}Id&sX-`!X^xFPtLX7iiJimDH;MF)-Vjgy3MED28>wSN>UhIZNhl!Q_ z!d8IuMnL&3H;Ss%G08IcBi=bflX*R@Lc8TW8~ADj%7FW|Mbw`DYet1o`tPIQZ!Y^W zqQzB@v$XSrumd!i*4BBrgr`&O&gp6`aoIsBrE4s}wv zPXdqd`DkGobkss#*SNHtm5?6!le#&!<4mJ?Db1*CN*;CSt(*9+O2VCGOO|v-HGB7X z7PjM)nQD1yrSmQtz>eUSZjiSO%Gv2;>w#yPkPKy~q8jasb!C^B59;QcSL-NpZSogs z8nJKBNZWL-FI$bw&E1xIb$s5I+c$kdZ+7W*T5o>ZR?p?_6hA8!xRz3u{;H1P_bk7g z%`Hi`T-$P&G_`$23Yt{1m>}VODacg_B7tkcADCuSy?^JXd@BP4b%b^nQ@qC~$cszg zW6E53+X>824P@#rGvn1Y~^)Ss3`ZY;ly|{%?XN|%kF5=P-l`t}_ zC{MBr{jDBFzs#LK4_N4%Cv6hX%Ted`*W3vM?T_nH!j$Hk@l>lx+;n>m$WU|kX@lHk z5UyK>pJ1y1eJdExN@*nI4Afvn&tFfj$#{MK+Z#Jq_yB;~1sC2q1!xkQ+U+)nIM03T z(>T=0r3U3>(GZ$G^uSFPawZWYd%D;rUJw&bu)t_QpDPJzO{SaY*(@`1x%8Q}v58Zj zz%VM-cp${B)VNjI^0I*aVe7A3cTav5o=N(+Kjsk>_@fx z@#66Ztb9jLe7QCPbG2&rA(&HPA^Gjsn?7M^t46X@d^h>94c84pM3q59`QIw+H9R`J z@vw)JuiEmey=2n!$0t5TbnRQO{u9RCGo`G80$cykYZQ=w8Y`P{)_i=lWS>LeGuCdZ z<|(;%+b6|b2|nMlA%FAu@^aQoDIUW|!m0)Yb2;dcGEbT2rs$e*-~2HkifPd}otOre zuJI3D+?7b*BP%X4u=d zWo=^_molug2_8fl*5Q_@@+NjNIy@c=CVW_|U)>R&)wM#^boABh84P9{VSd+c4iRd8 zc4GJK5-V-D6H$M$=+?E;C@O~dHrib6aVo7|VAqr44_~}+E#Klb!V(tCR{NE9wiw@3 z>S@-Ci?TRYF&fnEQamapkJiV{S7 zrH-R0#I)={$0|>uVz4ISs}+*^UTNy9W$t=T2iD0tkO}xlM4C`C!OYYp*L03OVVt}L zAGC`%hOi?6!daFUO|WA`wG{X8r!a}RNlEOKUK@!yM5dj{5iD9lHlMxN&RWHxFb9bk_i(66eht1IY;{L9?LU0a9?+U^BKiq>i|kcE6OoD%LOtgm;mV0P z82N6+=~&d!#~zxH+bIk3KZE<;l0uT|vD*vd><+1lAd{p{g^(zNfpdXEQFSFumFZHGwy|b15J1#BsD)*z>2iPQo}cl;25z9? z`fy2f|AW|=aGR6IMKV^QUPa~hWU_EO*AZsQBj+AZJ^}II76CCK16twe)gAm1d^BhT zEz$@=XLGWMc|<)R8=b>w`Y=n+8aJ89oSY;y85W;yInWf^$&a3fD&{=s5VP8}Or5=p zyOVCzG*V|s@l+QidBgX9zRmAgepV-w(MJC^F;j?!uH%(B-dW;c3H8^X<@RBrf5OxqGC331cnC|pz)4TK3H!RC?oIuKeY>eid|w?1SJ$|c**}L7 zLpFv<4?-E43lKdps}UvoQWST6xjAvw%wGZ%yYff|GZ@WoKsUQUx-NMQZVE2gg(Zd& zB}l-3_Jazj=d%>07^}c1XgZHqxBR71xOA80A19*-;`GJ^rO=T;VxC+ZGk{{13b{e3c;oH-B~^@l&!IQQSk6mJ z*1px8cU;MRd;ouuBx#}Wh|(sEw*hU|a-cSYMS052Q@u))^+EVNZiN3i-Tg!vWqqwv|0PiS>POShx4- n-%ShvghE4h7)dJsyYR{ZN<=4cpGda7|7hx}+A6hAt-}8YmrUn| literal 0 HcmV?d00001 diff --git a/resources/builtin/repo/desktop.png b/resources/builtin/repo/desktop.png new file mode 100644 index 0000000000000000000000000000000000000000..adc14c782ca05eea1fd332cabfd64eb3e69bb1d2 GIT binary patch literal 1688 zcmeAS@N?(olHy`uVBq!ia0y~yVAKI&4rZW;-{LxVAm>wnPlzj!n_b*HibhTd?7h#Q z4vh6>B|(0{3~aLIsZ;k|e>#O#%z4@WrO9WLTy_sv5?@}zu+-@F&j^W=zMz8J)@ zZjHJ|!7H`A=SIeJPbVaveE8?V2MNiKpQQdODz&x$oSpLi-reIzW@cyF+bMesojM^H z7jyIwi}u@hTG79vYHK<>N{T{W>bP#@((Hfno!zf~#ojt!1wCCy#^n?K&AR>h>)H*E zpQv_SJIL+t#T@E$^HP9(^_N>rxhq$d#;?D@#M0r*z`(rT)5S5Qg7M8kR>lSc28Ip0 zzw-NV$ZTsh2l@sA8fFx&T-)#eDtFqPFpFbue6h*~0*4($LKj5NGB7qazWYDw<<*n7 zE8}t})QPBnh*RuS*}EZvsWr%Q$`q~83oF7@rbfxSyfQ7Ep4s4|EaE;>?ZpVWZ(N) zcl%%d3P1kq@6CnD+ANI<42!}xycOVNUzPBmcV>LqdEYy~C;NZWPF`z!&1}ndx$N~l zTfax-X54>v>{i0TCRT1Sorn!!#^u#=EH-uf?o+94Ps^a!JzB)kfE>i#DEH zy6$R`TC!`*{6(>XoDrYd5Dv!WykEv^#DcHqDc7ECX8*eDkOs$s;O*kUx3{h3-~R7WbMdc6Wn-_{&?WEjxU!uTwZ;xvNZ6aoxqOuQ>{v*WGpLh<1N* zqbr(2Fxuz1*l~d;X0p3`4a(nLT3h{H@CD=Ds*V6*xr-~0`wP5zX}s&pA6BJ`pIv-= zt9m`|U0Ari)}-<i9(uUYWW+UCZt2B!U+A3D}CigG=46jaqa)VTBL6pfv{ zzr8er*gpGB3tqBF=-S+cKB7I=alSKOJ>HOO)T(xPi)p_`NHF*5R~n)Ghm$sImhNOM zGYwk9nRaxR=Cw-dM8;TbZ2wX{M!ka?O$z_HB()ATqUQ<-*#S`?`dz1 z>xIl_rX@k^Hgmg`2IuLXd9^Tt|4rA|pjGB`th`g#BW literal 0 HcmV?d00001 diff --git a/resources/builtin/repo/gears.png b/resources/builtin/repo/gears.png new file mode 100644 index 0000000000000000000000000000000000000000..c08e733e0019e8e8bbea774c4c3407c84dc1ca78 GIT binary patch literal 5903 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 D9mo~D literal 0 HcmV?d00001 diff --git a/resources/builtin/repo/globe.png b/resources/builtin/repo/globe.png new file mode 100644 index 0000000000000000000000000000000000000000..bdc379aa78ed5faeeec9acaac99ec011b7d1e54d GIT binary patch literal 5820 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 VPWA6h>8SpT$6@eJ4US)5`xCiLet`f0 literal 0 HcmV?d00001 diff --git a/resources/builtin/repo/mobile.png b/resources/builtin/repo/mobile.png new file mode 100644 index 0000000000000000000000000000000000000000..ddb5dc21e0b01bcee97adc44e213b97ec14a9f79 GIT binary patch literal 1905 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 literal 0 HcmV?d00001 diff --git a/resources/builtin/repo/servers.png b/resources/builtin/repo/servers.png new file mode 100644 index 0000000000000000000000000000000000000000..2b9f2c3d85b52dfe01e2b29216dfea90b14cc915 GIT binary patch literal 1800 zcmeAS@N?(olHy`uVBq!ia0y~yVAKI&4rZW;-{LxV1_maU0G|+7AUC_XcNC4}5U5km zm<3D+Yf6Irf*D@@`1b$fk=D|J_LIM+n{o46%>8}A%JKR(f&C|nO3IVA?qp`&Ta|h3 zPPL71-J%W7T*9|!PH1ed>8hR7w(gOZ;%dF#@GRqQW2XS)fCEWT)WV?E!VeVf_-7}`!;c($*;cXGdp`3z0dinL={yOuC+ zn!ncgpMA^SS#v^#B(6-^!oqndooC1K??#nJ^AqN+Ijn!W!%qDY0|N`Yr;B4q1>@Vh z&1J?u60Q#~r`g@!mJ3C@PTcpfGWJYQWqteRxlozl9&L3dpkJ|qt~k$36|X6KTRL5w zZmv#J3T%xyq9nGl!&N6qup7t>o47J+ZB?(-)$D6ZVQO1nUs=0+|CRg;8w59A%Dm&^ zIm=9WTKwlKuZxRP<&w5$-CdS@aBFrxQ|XHpMpmWgYS-v#vBmn%$orbI^1ki!ja4fo zwwNVWomv=vF8OPiVMcP(mx;mgNtPy4gYA=UMtz-rxuNmMCZ0*h6_O&^PA7A0)Ny`l z*b^~L@6!uMozn%CJqpuOm)N)op1$NRx41J^(m2fT@hXASW^sPPJR5U_txqoeza-{( z*6O5y!!0v)+BMa#Z(Qbenal60?~IqWsWUHXJl~jhZkFxx2hYwKH$Kzf5T#nde=q%^ z($a`I21hl zNk(s0%<)}Ik_v9N>@@P7<|kY%mt8hJF_`P!D^uYYyH4#YoVef8X#rzcMRoQIO49x0bN%H?z&VNT6| zyvid-1QKup(>s}!4Fhi)Uwp9Zux1a6j#WGQzE@ggTsZu?w{z;n#Yd~ZPS5RMFRZ>G9VPW}5#-neXU zXKLaxy#v-ezt;Qf+|Stlbdln;waey&86-ddkT^%i4j53sLKOFBKG>Xdx$n8nwcq+{ zSBu}dF0OXLFf#A+woT`^XL@b?xLa}B_5S%@Mc<|?hDj|A)?ari{?~QcoyP>UoBulB zzVhSJvRnLpYaT*#+*E!@-qTK0ni%lS%S$;>32VLu33gn4|Mv33ga74<_kp;cu6{1- HoD!M 'applications/diffusion/management/DiffusionRepositoryManagementPanel.php', 'DiffusionRepositoryPath' => 'applications/diffusion/data/DiffusionRepositoryPath.php', 'DiffusionRepositoryPoliciesManagementPanel' => 'applications/diffusion/management/DiffusionRepositoryPoliciesManagementPanel.php', + 'DiffusionRepositoryProfilePictureController' => 'applications/diffusion/controller/DiffusionRepositoryProfilePictureController.php', 'DiffusionRepositoryRef' => 'applications/diffusion/data/DiffusionRepositoryRef.php', 'DiffusionRepositoryRemarkupRule' => 'applications/diffusion/remarkup/DiffusionRepositoryRemarkupRule.php', 'DiffusionRepositorySearchConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionRepositorySearchConduitAPIMethod.php', @@ -5820,6 +5821,7 @@ phutil_register_library_map(array( 'DiffusionRepositoryManagementPanel' => 'Phobject', 'DiffusionRepositoryPath' => 'Phobject', 'DiffusionRepositoryPoliciesManagementPanel' => 'DiffusionRepositoryManagementPanel', + 'DiffusionRepositoryProfilePictureController' => 'DiffusionController', 'DiffusionRepositoryRef' => 'Phobject', 'DiffusionRepositoryRemarkupRule' => 'PhabricatorObjectRemarkupRule', 'DiffusionRepositorySearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod', diff --git a/src/applications/diffusion/application/PhabricatorDiffusionApplication.php b/src/applications/diffusion/application/PhabricatorDiffusionApplication.php index 8fef05bd88..c07c89159b 100644 --- a/src/applications/diffusion/application/PhabricatorDiffusionApplication.php +++ b/src/applications/diffusion/application/PhabricatorDiffusionApplication.php @@ -140,6 +140,8 @@ final class PhabricatorDiffusionApplication extends PhabricatorApplication { $this->getEditRoutePattern('edit/') => 'DiffusionCommitEditController', ), + 'picture/(?P[0-9]\d*)/' + => 'DiffusionRepositoryProfilePictureController', ), ); } diff --git a/src/applications/diffusion/controller/DiffusionRepositoryController.php b/src/applications/diffusion/controller/DiffusionRepositoryController.php index 91b33bcaaa..72b4d105d2 100644 --- a/src/applications/diffusion/controller/DiffusionRepositoryController.php +++ b/src/applications/diffusion/controller/DiffusionRepositoryController.php @@ -274,7 +274,9 @@ final class DiffusionRepositoryController extends DiffusionController { ->setHeader($repository->getName()) ->setUser($viewer) ->setPolicyObject($repository) - ->setHeaderIcon('fa-code'); + ->setProfileHeader(true) + ->setImage($repository->getProfileImageURI()) + ->setImageEditURL('/diffusion/picture/'.$repository->getID().'/'); if (!$repository->isTracked()) { $header->setStatus('fa-ban', 'dark', pht('Inactive')); diff --git a/src/applications/diffusion/controller/DiffusionRepositoryProfilePictureController.php b/src/applications/diffusion/controller/DiffusionRepositoryProfilePictureController.php new file mode 100644 index 0000000000..e6256989b5 --- /dev/null +++ b/src/applications/diffusion/controller/DiffusionRepositoryProfilePictureController.php @@ -0,0 +1,246 @@ +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); + } +} diff --git a/src/applications/diffusion/request/DiffusionRequest.php b/src/applications/diffusion/request/DiffusionRequest.php index ab08025349..1a46d43adf 100644 --- a/src/applications/diffusion/request/DiffusionRequest.php +++ b/src/applications/diffusion/request/DiffusionRequest.php @@ -143,6 +143,7 @@ abstract class DiffusionRequest extends Phobject { $query = id(new PhabricatorRepositoryQuery()) ->setViewer($viewer) ->withIdentifiers(array($identifier)) + ->needProfileImage(true) ->needURIs(true); if ($need_edit) { diff --git a/src/applications/repository/query/PhabricatorRepositoryQuery.php b/src/applications/repository/query/PhabricatorRepositoryQuery.php index c7cfb4df5c..85b2ea0f0d 100644 --- a/src/applications/repository/query/PhabricatorRepositoryQuery.php +++ b/src/applications/repository/query/PhabricatorRepositoryQuery.php @@ -36,6 +36,7 @@ final class PhabricatorRepositoryQuery private $needCommitCounts; private $needProjectPHIDs; private $needURIs; + private $needProfileImage; public function withIDs(array $ids) { $this->ids = $ids; @@ -160,6 +161,11 @@ final class PhabricatorRepositoryQuery return $this; } + public function needProfileImage($need) { + $this->needProfileImage = $need; + return $this; + } + public function getBuiltinOrders() { return 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; } diff --git a/src/applications/repository/query/PhabricatorRepositorySearchEngine.php b/src/applications/repository/query/PhabricatorRepositorySearchEngine.php index 78f29fad1a..f321a112d9 100644 --- a/src/applications/repository/query/PhabricatorRepositorySearchEngine.php +++ b/src/applications/repository/query/PhabricatorRepositorySearchEngine.php @@ -15,7 +15,8 @@ final class PhabricatorRepositorySearchEngine return id(new PhabricatorRepositoryQuery()) ->needProjectPHIDs(true) ->needCommitCounts(true) - ->needMostRecentCommits(true); + ->needMostRecentCommits(true) + ->needProfileImage(true); } protected function buildCustomSearchFields() { @@ -165,7 +166,8 @@ final class PhabricatorRepositorySearchEngine ->setObject($repository) ->setHeader($repository->getName()) ->setObjectName($repository->getMonogram()) - ->setHref($repository->getURI()); + ->setHref($repository->getURI()) + ->setImageURI($repository->getProfileImageURI()); $commit = $repository->getMostRecentCommit(); if ($commit) { diff --git a/src/applications/repository/storage/PhabricatorRepository.php b/src/applications/repository/storage/PhabricatorRepository.php index 889bb734f3..a0d4c6c7b5 100644 --- a/src/applications/repository/storage/PhabricatorRepository.php +++ b/src/applications/repository/storage/PhabricatorRepository.php @@ -57,6 +57,7 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO protected $viewPolicy; protected $editPolicy; protected $pushPolicy; + protected $profileImagePHID; protected $versionControlSystem; protected $details = array(); @@ -69,6 +70,7 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO private $mostRecentCommit = self::ATTACHABLE; private $projectPHIDs = self::ATTACHABLE; private $uris = self::ATTACHABLE; + private $profileImageFile = self::ATTACHABLE; public static function initializeNewRepository(PhabricatorUser $actor) { @@ -110,6 +112,7 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO 'credentialPHID' => 'phid?', 'almanacServicePHID' => 'phid?', 'localPath' => 'text128?', + 'profileImagePHID' => 'phid?', ), self::CONFIG_KEY_SCHEMA => 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 )------------------------------------------- */ From 6cb326e58e41fb283956fc9d379c8e7bfb6450cf Mon Sep 17 00:00:00 2001 From: Chad Little Date: Mon, 12 Jun 2017 09:24:57 -0700 Subject: [PATCH 03/34] Add a background to repository icons Summary: I think these are a hair nicer in the actual UI. Test Plan: Revisit /diffusion/ Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Differential Revision: https://secure.phabricator.com/D18118 --- resources/builtin/repo/building.png | Bin 1538 -> 2566 bytes resources/builtin/repo/cloud.png | Bin 2821 -> 1904 bytes resources/builtin/repo/code.png | Bin 4346 -> 2680 bytes resources/builtin/repo/commit.png | Bin 3028 -> 2103 bytes resources/builtin/repo/database.png | Bin 4716 -> 3428 bytes resources/builtin/repo/desktop.png | Bin 1688 -> 1193 bytes resources/builtin/repo/gears.png | Bin 5903 -> 4209 bytes resources/builtin/repo/globe.png | Bin 5820 -> 4171 bytes resources/builtin/repo/locked.png | Bin 2888 -> 2092 bytes resources/builtin/repo/microchip.png | Bin 2456 -> 1841 bytes resources/builtin/repo/mobile.png | Bin 1905 -> 1411 bytes resources/builtin/repo/repo.png | Bin 1950 -> 1590 bytes resources/builtin/repo/servers.png | Bin 1800 -> 1400 bytes 13 files changed, 0 insertions(+), 0 deletions(-) diff --git a/resources/builtin/repo/building.png b/resources/builtin/repo/building.png index dd39fb8f140f158dc8676adebb509e0771069baa..1638c4174dcca9d964625cbd884c1b48414438e0 100644 GIT binary patch literal 2566 zcmZ`)c{Cf?9;RyASIe|KrL?qK)vBt|YAw_0Fs-GQ>9lIAP^vuIDk+U!iKtLZ7GjA| zLM#yy5;Rm1BqFgUu|+J2eP7Z}r`5-q_s2Uk?|tXH_jk`dzjJ=)e)o6p2fbr&DR)Tq zkc5PUoVC@>yAl$Tx_jfG)b5UbQM9Fm#J;dQwhp&Ge*Cz;zR}&o#T3;>fpcDjBVrQr zipv|=y+dNLc$7btlwSPgMG7JZKRdU;9U6~{&z+fFSY2I*B)?6D7r$@qZtLhl=HPP* zh`?}o3KI7$Bo!D24-AC`yi5-YgSXIFf(cPg9WCq?YH?|W)yoTwK?y~3jPAj;wT-p) zjjgTiU2Jad1~H!4oR(3VkW%L3sn&(?HRg`Pf=)Sp%WwLt$whG8f;{&W=mOkQ-u)^|;G5~WQvGanI`6ZR?# zoRlw|nIGd%v3huksYSsN$g0{F6sBr?LKqD}M}l)ivkMbbGw`embYTrFs~qy?Ef|`= zyu7-yx<+RX42?`+%j)Bk3lP~AKQon6BqR=4S>H5s2$fvwg#<~N{ZqPHqXew4?X%Eq z2AYhzb~>X#^Tck${ug{_l~GQfgy#XPI=x?iQ7+TaVTW=c;gRL~J(mD@-l0vdbVQY| z2B5m9Yl9=bc)

^dM8$1*dJ3iO&}_mk@Sv2*X@Kn%%|B0fuX31(6j@qEP*x=A*Q1 zcJoNy4EUc5c}p?7yx|!xrRaf=&%wrfSE#a+SXm;#$4CD1Wn}gqCKa331tedM^F{s! z(jnWXb-wBVv&N2bV%gi%J2uljDvgO)dH#p4OrukU6zK5P6CgfK-+n% z1hHlg8>8q(3QydxpVDyI%pBn9 zce%O~6lbWDp9zvmT%=0X*x_`wX`w+dLZB5I&UBl?pJ}$mob6YzyIr1kMe!bd1$DKU zNk@7gy$8?JfyK7p0PF3XI_mXzYEc*rR>djp<~(5S$?MuZHj_h|#crIf8`-%J+zJCJ zUi0O4HquEM{QB44@VG7^B1ohpIqWin&xnPHl&cxryvjn_h=uT_Nj;eE=|IsmNU68BZd`n*bcSoM3Hl)eF2#8XGKbox%>oXJ z za+@DL(9pK$-g`q(KgY1c-4^OSTKBW2xZ+gYl*b*te4pcezwX!l-;$l;rgmNS1#tq! zfmrJwOg@ff1Ki~ejRm$V3He)}zUwjBPy+kO&zEC@5be;A*cX53-JNyqW;{Ns!@E|} zdFx@X_o6b$|fE|7pwi$~gjRAV5d2<&Sl-IfjzM~vRVAM6pAw?z$ z_TsX7Ukfc3?dE**@hLzf&Q>T2Ju6HpRqku)^as&Z7}QT*Q!8iJfcgB;I-?kK^b>hl z=Y2|Rxau13H^;$k-fx&4DzW->%3kM$#;!h%R}NKW7K!QpW}@R6mX5hn=9ogpnT=y7 zx}6X`VZ3SSpj+O7V10oc6}ZxIa$y7{^q$_Q)2SWQ&pHP-R{mn1<-A;_jA~YGU8l??No)Ax;vi5gQdj7 zGJoTu9Wl+)Q7q$fU)NLNoFiv)e{*^52S0ra=?uB~ zZn$dFuwfwrl}K<>p zv=cwxlzV>m_^;TCfCYDt-J`+Bm2YqY`>^OQk%Vbz+V|0|okMGzw$NY>)57IT#Yal9 zMSy2c#T@@PYLE#mW->l;=XhIZt`MUp>)S4AaHG%f2fPF*n`d< z5w4GY?>Rf_gr2xQa{TJEMQ6h%O(TQq(#ra0hT6s&-h$otbPJkW{aAL&^uJb4T(4() zLh97@)5dKK3@nD8E{-7;jBoE;Ez@=vaC>OAz$!t;7zA!7`rZ4ld5CT2G3~eKvUE$c z-@o4VYu%ff^(rn15MsBt^7p%1$Ki9%fW|<$V68A-9IL*hFcWXYrSlPcs~S zy1!{Ctx+vD(OH&Syya2R7L{e8)gpq^X0;tLS)z7+ah&PV?y2=A3xLdhUI&@Dfi3_O zS!V9ddi7rGD&^MRUfi+4EM{NJ9TWFxJ@?y5w>G*9Ccb^O`IwPmsm{yI-(vd8j!x;F z2~?F5-#tri>YOaQj6ilh_x4GbUu?1L;_xmrpY?U$(pJrrxvySCywAR8QTZ?<@#V>j z>z)gqe^8moh!GHwz%e|K+HjhoJg#V#0dq|I;+K0CR~AqC$54L1c1+t64r-9S~?d;xYRNb39pq&PuyZx?rVdG%SlX8!9}maFc~&#gAs zTjTt>Ox>Y#&)u6>(|c2e41V7$Fn?u!saI%&?C(75wQHN}SLVvj>HFhdU&I0nbxZbZ z6Ij-S`>w3be-R&bU)rkn|uy3;J51xOk*MGelIzQ|McX!>_6&oTZM%-T!em_hlY3NfXtyJ~?KUzy)`BtZwgK~Ag`|}_-K?Jxc Zzqw3tgRE1!2C$%F@O1TaS?83{1OV)qoLm3^ diff --git a/resources/builtin/repo/cloud.png b/resources/builtin/repo/cloud.png index 7c355b0adc84896144f15afcc0c1fd8f8a346122..be998915c9349387f171d66757fcd8d841b33459 100644 GIT binary patch delta 1889 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 diff --git a/resources/builtin/repo/code.png b/resources/builtin/repo/code.png index f7e56be76276860087e987694d3397d22689ef74..3080e9df8862a3dc50f98b10309ad8e830a834b3 100644 GIT binary patch literal 2680 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 UO>b&6G5`Po07*qoM6N<$g0GBq#sB~S literal 3028 zcmeHJ`#Tei7azT$)hadA$~|EvVpeXMTSjvmb1lm?wkBy4Aw?!KCYOW}BDcw9MpAB( zCdI}`uF+gaNO)a(^?ZMO|Ag=Jp68tBJfF|`;XKdhIp;Yi#@f;p1cU$q0077gX^aK{ z1Wx}6kzG5CW!_y=06>syjj}V@f%sdL|NK7%{+|?Ry+R$2Z-oCG6-=}8yKbBX2&d>6`4fXfb#;NTR zfcX?|{a%=!d>dqROxC+$?eC3&`wGft>GhY@_n`9Z;6(1P7?Xq-Zni5mfoF==A6KOw zlzBO5@Ygt{QAP2?(s^IY#emBF&A03PKpCe`Jm?;g*I;yg8kK6N=f^|Bli1jYPluH{ zkfqGsgiZb2*H^Y*c?q*R({jo~IVqUnNJFhl5qdTyc*)~Bb8Qu2ccOF=Z!)i!?Q1P~ zC)DC{n3ha-K9}|Jkkd_VXp^T0)g1i<{6*sZ#a)VxKL7yX*Jj2Bc0mGjU6F}@w!Zut z;VbjiZ&$tB51>b7u{+GaO*dvCd!*qvLJb^m?6GL9p7P1_*1BPZU6~!8q<4GeVpZ=v zF=VUBAC`r>w%qEjNNw= z@})bS3Ez8|JL#*=+THEUPtGCY-oMtd%~fjq)-@Q!rsmd`wclbTm-BJeGnzOd@0D@Y zm-a}$_V5q2*q9$&`jh8(y&F)y&)noyDfq$Xz8d9D%rM)HcZ17}ddGqCR9vMvSvd?>d%uZ)iC%O_%9llsnL z60%&Ka~y8)w||DoZLsBNwqD#4jK98f;co!V8FbwE63DO6szi3(w>qbe0fA?7@%g4D zqHc_qb{h!8{8C1oeR!KDnR)bBVNl7wzv3!lci~68O0@}~7T>9=#%JC@hwl2jO zsnU`z((O4*90OVsRIEf=62mMoq!)19my>?H(g4ymhl1eFNrV{4mpvG~ zEU~Grx6!=l6roPMUh8wWtj)ydlY6229*c(}{2HR}wrz)3heKCfign9*NKNrDZc{pj zL(jR1&mpVBio=)Ek%&k=sjW*#^>r;2h@9`h4cnv+3k^*qVtHT4Q!MBAN4;RYT>m`jl} zBp1=v+G+5s@ZFNV<7=}rq5h@N*0}uPA4em!cR+sJ za)T<~XuL>cdO{8%IuxQ{O}l-n^{z6U4?Mm$Lr zz2%A;cf4jKg9*h`JP7wZr(yA=J&&)P$t9Gs9AupG69?Mr(#0zI9JswAQlf-Vil>&{ z_OkGZx)M!nvV~DFD{2$RN_L)ZNT=INNLyyW}9V|RR(n8bBAr4Gj)u2wumP8>PV-F>CX>xUu zPtxn!1~veddOdJ%9hf?2;79OS6g`2jbQ*D_R2h`L?>T2bsYoq;?@HO>pAQ(*Jj9Lw zVxWAswzzGu%;%KOJMW=tAhstZH?P9yl^&I+tl}WLr+@WhJzhiUYLHxeWvXBn_Vuri z^-<-lH4^wB&}_i^oop>?lgSsN8Kww+^>`xWUNMZ|HtoxL#w$z+xVH^P|<>r^`zgt=l5i ziCkHw3ELyIp90Y7<)`~u*^=f?PEqlTQqk^YQh{w9LhJJsH6rO*rf=A^$c-CHQwefJ z!_&zO<;-6$=3@2 zz}AJZI;2cp_HBznrfxohEA=0A4ywpV-GJ<}7$lfH8Y(&vc4C!np50)eXferFPr12*W&ca5cRlQ|H)P?rjqlY)mR;3k}yOO^pL|a6RXr*{gi9^6Og>Jjn zisqBfEUeG)>*Mvs#OGDIr#yaLJ+S#yQH_(~Cj1#g4`3o+i)=q3bw*2^u~S=^w29hJGi{pV{$Mi`OXD)b Hs}cVIiSwi` diff --git a/resources/builtin/repo/database.png b/resources/builtin/repo/database.png index 2132b8504126bdfd63592d76dce49b971b272d56..651a2d5bf7c6d9591f22f1053d94cfbb810a929b 100644 GIT binary patch delta 3426 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 diff --git a/resources/builtin/repo/desktop.png b/resources/builtin/repo/desktop.png index adc14c782ca05eea1fd332cabfd64eb3e69bb1d2..0513d3876f9a8631a3196e03d67b7f33943da7ba 100644 GIT binary patch literal 1193 zcmcJNc}&^|9L0ZBC#X1p*>qJ&;vrHqHKOvVZrIZ}Q&z>yv!nOQ;XT*vP^N z003jpJMQ-Z0AzD=20F)$Pk9pLIJ|&*KLBgBTKR^OFI?{K8>dt=H7X%D8c7f=tSl`{M9X3xUxXo6X*B!Tyy{urVq9{5dNzeb zWt3I4v~{s3IP;Sn{?5)WGNrJlzH39Fij2p%b`J0FYd4i@RC)yog%emW6wxQg8A2OT(jFwfgP&6tBB)tgCm7(K^`N+8-X9qf%|n%q>iD z1*KF*5xHsW?e@?JcaS}uiKFs`D}>jy@K~%^A|qEaSJtFq(bBB>Vx{e0e}Yj-v`Vr{aZF8 zpyM~aC)Tr@x4qkDEuoQ_4o`BBlP<|?~8+WmB1 zqd<)aW{TjT!;fw0COM8=o?$?+h2w37Tj(PLk(v?P<0^BFy2tKBY#9?xREeLN4l>Su z!MXEJ|2`t{^g1|%%r+m*v#zaqN(nKSmrY;e^m|OPfNUJv@cLyv55%~0th_t}eNhi6 z0GW+zCM_RzAKnu@_ed!V^M(x(vh9j?wI-mS#Uo_`l4 zO%@AM;XX#Tsy#nRZ}-(YFFSr3-G9c?iKXutKCSat!zC9JgFeg$P8W3@`}R-<%8Vq+ zZUD^Rv~qW?!3swe<4xdqGciabB=?4#aW2H4Fv5M>_8slYpK@9NC@=BrX;?)>L){Z{ z?v)^KH;sMC?r%o9JM|B-)8-^aOL9S#N3#ZO?Sf{VB|mI7PM`3FUvRL6!asDdg~81o zoGMwNRkLvrG|>;i@W90&7_PXx){Gd^=UO2rxX8_sQ|V6rv8ox;Sj+i^6cAD7y^0FB zn$EFu(SbnM3oiRCx#jv=*v~KTz89th9IFqHz|CCK~Q_o^&zJ2(7B%W)-aPZfhU92d-ub#xc0s2{u@w4 XAkhwXBkr1^{G{*%`?%M+!BhSL@kn$l literal 1688 zcmeAS@N?(olHy`uVBq!ia0y~yVAKI&4rZW;-{LxVAm>wnPlzj!n_b*HibhTd?7h#Q z4vh6>B|(0{3~aLIsZ;k|e>#O#%z4@WrO9WLTy_sv5?@}zu+-@F&j^W=zMz8J)@ zZjHJ|!7H`A=SIeJPbVaveE8?V2MNiKpQQdODz&x$oSpLi-reIzW@cyF+bMesojM^H z7jyIwi}u@hTG79vYHK<>N{T{W>bP#@((Hfno!zf~#ojt!1wCCy#^n?K&AR>h>)H*E zpQv_SJIL+t#T@E$^HP9(^_N>rxhq$d#;?D@#M0r*z`(rT)5S5Qg7M8kR>lSc28Ip0 zzw-NV$ZTsh2l@sA8fFx&T-)#eDtFqPFpFbue6h*~0*4($LKj5NGB7qazWYDw<<*n7 zE8}t})QPBnh*RuS*}EZvsWr%Q$`q~83oF7@rbfxSyfQ7Ep4s4|EaE;>?ZpVWZ(N) zcl%%d3P1kq@6CnD+ANI<42!}xycOVNUzPBmcV>LqdEYy~C;NZWPF`z!&1}ndx$N~l zTfax-X54>v>{i0TCRT1Sorn!!#^u#=EH-uf?o+94Ps^a!JzB)kfE>i#DEH zy6$R`TC!`*{6(>XoDrYd5Dv!WykEv^#DcHqDc7ECX8*eDkOs$s;O*kUx3{h3-~R7WbMdc6Wn-_{&?WEjxU!uTwZ;xvNZ6aoxqOuQ>{v*WGpLh<1N* zqbr(2Fxuz1*l~d;X0p3`4a(nLT3h{H@CD=Ds*V6*xr-~0`wP5zX}s&pA6BJ`pIv-= zt9m`|U0Ari)}-<i9(uUYWW+UCZt2B!U+A3D}CigG=46jaqa)VTBL6pfv{ zzr8er*gpGB3tqBF=-S+cKB7I=alSKOJ>HOO)T(xPi)p_`NHF*5R~n)Ghm$sImhNOM zGYwk9nRaxR=Cw-dM8;TbZ2wX{M!ka?O$z_HB()ATqUQ<-*#S`?`dz1 z>xIl_rX@k^Hgmg`2IuLXd9^Tt|4rA|pjGB`th`g#BW diff --git a/resources/builtin/repo/gears.png b/resources/builtin/repo/gears.png index c08e733e0019e8e8bbea774c4c3407c84dc1ca78..85d8392636b1748428647f20590d21b37ee98c10 100644 GIT binary patch literal 4209 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 D9mo~D diff --git a/resources/builtin/repo/globe.png b/resources/builtin/repo/globe.png index bdc379aa78ed5faeeec9acaac99ec011b7d1e54d..d30feee429c2b16c7b682c7ec885706af98d8491 100644 GIT binary patch literal 4171 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 literal 5820 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 literal 2888 zcmeHJX*3&H8%`}lZC?$4fq*bkbDb_{2^K?GS`eL9CTeJ9FlIXXZQS`~96W_q_Kx?|aX^_dWM{o*y^C!rVxZPl68s z00S4NLoi@=>Gb{`ucU96uTdjq zt7&?_#P1{X${ZL5D&R_cVwwc*YQC$v@|ACGd2xRGSNc%j&xYqLf=JPlesv!|QNUQp z`iJA<6F<#`N1=Z!zwQ*#-EeHv^=RkYJco?3#QV^;u^Xzdy>+`RF*cyjuU2oSg=|dw zCWzp3AI(_ZF}{7?#2-;vJNmNf#babjOJk--`&RQK=5x-6$*_BV!2kNxetxMlvN!*fA_j*OIrLe&(eX4u;9^3pAr8QSHA zmBkYDNi=3UZD4@-cuPVeCs-*PYM+lEEa!#QD+e;e<+`YpPxGl0yl#Q(U$d*L)o&W( zog^l0ct!h%KzafKx>pV4C8jzK$ho7Rb!@_-OyWGz_qkIqCFeIAHdwR`!z9XFq)am9 ziU28hEN<#)Kc3BsTRlm(cy25%Bc6%6D1W|?%~a>jUeR%15%q$IuoJMtGIj1ehRa+9W zg|WMVT-ZdjjquTv-F@za;ie-ZU^h#(v2-eWK`29xawMWcDq)7^xLW_7@GqWp{;uNL zNT~>oeEu^@cBah3Zh_Wjc0-!`GX(9#aOM`aMbobB&y6xeYP7j+M?Fqq;r@cS9kMO)$cEJb3N};|J zuC5n06b7{}8_vfRHdD?{vT9`fz@`>EvdP0U^4vIo@vY+$qcwJ>PH%$uBb<1I=8q<@ zeNZk_yKDlb4xj(C=e`Kq%gUsOi~gi!8G(YYRQzTlY|rt(M=BG~EDOz?IPWoy)M>+L zScW>cq;y9jR+%I8;3R}>bJU4YMHjog9< zAV3Dx&vf*+%bVV@SG}Z4ehD3xVxBH%dOy>oDMCszrmLa3;PQ-%gM+M5Uixh64cVuv zI!<-H397i*igVGtVqll3v}51#NBY0u3Wpu!szuJSF#+r4HL`j}jgvqht<@?hQi)j> zYR%4Rpv;2otFh*?v#hA#@j~ z-}eAzaPS2EoYR~W?g{KEV;1eU>AO(j_a==wZWy-t6T~_aHQF3AbKu^?yPw_My=6KwNJDyN3_}#fH>N0!G^i|uJ=?h+Od zWCjWHDR|jr&xsD?zgB9e-s;-K_4htM+DbIiD|lgA%a`_A7_BE=K-2p@I}ep?ro&Xg zPbGg>?oYWe=YrNi6-GCCsof(mZAPgUYl|%s3#$lee zN*qUavFwNl6nJyy6-=I8q8qUFIo-9IulKif7t&EQCH*ciM9z9i#$yfBQcdzmw<1kg ze-s)YPM&MS@QvZp%&_)c4VC%u=g6LX;02%Jx^JYI?i?GW;C>l^(;FXk7PnEhOlWP#Ps6-yS?>UHI+ zdTo7URi&O0&*u~o;EAP(Wc1^N5@Z>vu#^<@q%^O%zNWsNL}jF8;k4QK?Og*stkF)!5WRb_mp$6uJIo#!Pe{WgrejjGs~*K5BVvovva8D~ zsnR9I=B9RYbF;Rgy^7FQ+t2||EEyi-3#P=Q?(1ac<<=qy45#pPrarm?6T=5>Xr$oqs zN@emH(fr)JOtz#L9_91+ua=fq3wZtc9~h zQmCuubKgSE39uS{v%`%iI_8VIbxvgAq4`B^R;rw;{yLY^Fh#T3y8h@Mn-=sGH2t3C_T2if*l5QPjm*llEqA}C{w9eUio0_j zBKTyy1!-pCZJ!obyyxpDQR{iy9EZfJ#7E6sGkjWa=~P&V?u?;7%640T8S+cUagUQpc9>i5um7DX?$~eP96382 z1|9Y;HTUwe)Ptpyyeh3RqEKVf()7q7f(0tEobIVocf{{J| zT5RtcngH&{J+k(utbbiWffJSTV3s!-6V%`hxpXEZ-%k_6Xm)yKu8(nTB{SI*c1O)&9 literal 2456 zcmeHHSx}RQ7LFjO>;xN744XeoB&=Z#F;yglv=9_9tc3z4?1DlC3W!w-H$ngtk^&-B z*=`V!fM|mapb{dh8cK@nn_&sWvP2pdEq!u2W9L5Jm!A2~_C1~X&Y43xi^nR;9hC!t zK#DjQCl3&4AN(&rD80wvE3RNcAgPSAu3nhEHada)FaA~F|Dr(pMD*s~2@WNC;5|VH zP7%wyN5?0ITC+UN!k&JhAq?AAuYCUIuI=yjpH2Sf&aVCT!@NIGkmUr^3Kvy>onYX& znuao+_nJR-ukJ;z{I%bPWBdAlvi|SbZQ~geLe!QxLbBl-y?O2on6o16=v0!GDJ{v@ zH*j>uoYp&{4m~!~aR1lJZwvQ1+^YW3>g3zScRrDRF?hweCia5`W_wvt@v9rpEsWqt zwPpqLkA6;bt*ya&F&?|^mzJVj?OFOo7j~kHJDA;Eb?6K9j!okea?13aw&=Q?HBl6?R*VZKF!oac}d72MtVv zk%;tWRr+op*m!yI_ibG^R@ zxgre2_nVu0p=NrP)67nNDFR3{c2~G%4Cc!4!`M;$dyUb(WW(>0j*ZJZ!FE1hyS0OM zf4NJ3eBr|O0VAk!$7DXj{%Yl#yn>w4bY>O|YK*eVR6C}61Ovt(s2WwF980PlB?5&Y zc_Rr@2pm8nMr%de;0g+h#u()SrU%8Ls+tr-8?YPcnzo@_^SXd_pU-HkS(&v9QD6qv&CSh3 z%tsNRLmJ-|92S>wYYj-?cpVEs3@K3q79q)XgiuQ^i~3|19w(DL-6k6LSBjK4$K zli7|LWnD9`z5T`8?K-%FYj-US@+rXKANQ37C*EU2K1G*Kr|J6ZLei^-;QMZ z2yF{AG^m|(<>s0u>d|V4nqOa_;SWvG6=lmi9ZQ=yFRiWbI;{M(Qq)Rm~ zS2f%IUcM1j_pu5~`mBYezx zP12Fm0=V8Al08El_^Dlynjy21q)TWsBwe+@r4eI2^dRWwF_TB8$)<+}XL)ao!v{+3 z*{P)hCQrT0LLnffCCjPx^6r*cvv=u1P(kvp_lE7%i`z)bf&qeb9!W4qurOdKi+yiK zsb;5v#}v^gr@fYImvk5+a?D&M)EmiPec(LcVurfT{hp)k2=Dwf>gv&(`SDuGFlevv z^p81WvR-jXDJCH~MVXc-Hi}cazrZ8|BljhN*@hmW)10Ue^RBQipu(mht#!0sQB++1^ukcpw zBN~lXfsfJ>&MD2BP7r=*4{(KEyITlztw4Sk%s|GG~z?(V7vb!WRR#2}xRXMMFe%?&Iu zLtmUfJbx>0Pt_IM8oMO)va${%51JI87W)OaNrJTFI=FyQ*RlV!r;oh0$5@i<5d_=i z;v^z$!%Uw8CHDN>n0q+fzt@YIS(rqH>D@Pkz18>Z{EBzV(({aF-h;U9xgydh-L>-0#R4CB#{ddivn!jnycQqk3akG)s(sr VPWA6h>8SpT$6@eJ4US)5`xCiLet`f0 diff --git a/resources/builtin/repo/mobile.png b/resources/builtin/repo/mobile.png index ddb5dc21e0b01bcee97adc44e213b97ec14a9f79..b4ec5ee3f17bf73acc177ea2e7b344e99523e284 100644 GIT binary patch literal 1411 zcmchW{ZkSK7{@WJ3}0y4t5(`8+w$5joo#yAT(*3#ZD!`QEUkI@Rw|{W_!g)IN+MvO zi1-SkA|k$!7J?=wiIhnAZlIVU3OKJeXw_}qZGXVNchBATd4BlZJ@>tD-symomLOXY z006M`_VWB005EaX{B)Bc`LWKw4xb_rouAsC*H!Y ztgJlZi}0ll@i#HiiD*HeI2~Eq(>F9VGh2YCVequ+nOV``2s9N3O~Z-ABmCY${$p`h z_mih$*~FwG7FrN@qhMl6k(*zUS5Vo})yM4;E^3yV+xYCZo^(WsWOy_dn*VHgw2s+D zu3(cZ*>^Bii7@Qld(}LF=x$-vtt_H?QB%))R8!BbVQ`bv3G=ViX}3u&?Y;e?;l3x& z9`{R9vx!YD-HVG$Og1kjDZf`JiAh3JYg#GQoRJrkQrX1PvNj{9RHxHxwK{5TYk4)N zS2)Dt@S8aNv}|Glt`zNDdq z%DNhfq5uFunzyG%V6w?;UgrDI02vemZ7Xff2m6m^k%v&*)@5x2^!tIFoD$!Os~369kG zo9K84c`$B*vZl^wyOeY$-AM0-HOmJtK!f9@QO2ab{>%FW{=ZGjgaGHVFu)9{Ym?B+wo9MvX<(-cEe@(@eEul1 zleTT$?22mU`^+cX-)lcsRkSId9qZOBYdm`6j41VH=uzmd>3zS@6mHm-PCYiq9x$cmL+t&fct)9f1a8h(97zj% zbI0=VIc$~o+Z=!GSAO`=ax)KFIIFTBlN`m0{1QVaIu7kOuXOwdyTA5$c^u2s@^fc@ zyn`tMFSM4GhaWkY<+4eB!1vl3P-z5aGlYC-Q->hY>g{#wQ((}kT*x|uXD(y|B3@vF zfOiXYhV_+j;~w(YdK)wA!FVsjZgRMpt=6VMWVOM3bqu^SC2wAH%*+Vhhy}Z9#|~8U zR%HqU^iqd96OYV|PByhep{xmZM7qt{-}gzsdsE!DLyYV3i4k%mf{PyF_PNxpm3R2M zU8C8;4X&Z}Lsnym-d*BM7@&T<0+?h^v@4?k6K?I0ll&x^ZE#CN_$!c_dyp^$d3vF^ zVaS~x_TbvCv`QW0h!e)Wbxs0w>csBcMiRBGU;nXu-y0jz6#BmeT5?d3Yu!0TAByRH MBEYlZhw!Yw03mzW^#A|> literal 1905 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 Cm`s%b literal 1950 zcmeAS@N?(olHy`uVBq!ia0y~yVAKI&4rZW;-{LxVAm>ehPlzj!n_b*Hibg^RFiB_B z0poi~NswPK1FuH>_K%< zi@Pjd<70c^$t=MHza5@aKEL5)`k^dwWPaw*Q+Fp0~nD5k_&(qf4{e%_8CYAp1=vcV;ckzZ>bvj2beiWV=J=aDw z>E)N1Yc`&n$GvgO$C_&q;!ZZPXKt)|8Pu`-boi#DyQ*|ut}M*ixb8lOV5xERn&|6J zE_cs~z4q%^x%+0)U2elt&FD416_?4SbbnR&6U#4eTNQI|o=vToRP{XFYuz8p_pX_` z?XJ6X^7^cq->m+`=AY```n4$IP2|Oh{L|f~FJyHhHY6NuV&xWtGPKp!Onz^#V#TS= zoBjIu^d;xYLkzARdKBaz`YI|;Q|$GNT~Vb{_7OT^)&9CO_gkYz z#Oe}YuxVRP_`xrg6S+F#WaE+g3m?vI?fSY?`OoXH>sn!-1pj;HqlN7n`P-Y>Rjr#e zdLGA{JQcp}skjZ8f+ufXySgIxee*Gy@>Rdm^3Q*-ZVLXNSS~G@eNK|))rT>QUg?+v+f*Dj(YVD2ZC$P23? ze1cfkdL2<&dSR81&nJecsrJInAr7m(7AN_(gsHDOB6EJ#!cgC}GZyFZeA%V+><0hY zSKB)@yQVvD@76vlV7}n)BQ`_lHv(U})sL`PPx5HLl6|r!f0D=K?b527=hn7=sr>(N zamu=5%Tzs9Ke_U3PsC}*?DPe9rY_2P@25L&`?=iJGa_u+{vUj}`fa%%%dCpHDW!8R zJUaKs&{X2;Ig!pyelvUzzwG-d(Y+CZcKI2G-H6z@`0j2A?U*$Yyc>=Qh4(zoVYS&L zp=}Z7&voDC6>rzk2>y?kXX*Tp=(*Z_-|F|DB*SaYe=_T*mFpb4)wTca%da363D@_Y zwiQeEZ43UNyB(;K&AhtID%tSbwW9@Bcb=B(-k8+>Fwyt@{f!dZVa(y%rt&BMyc_-v zNO|Tk)~ubWU~dq{-^BC9a9VEf+|IG)-z;#pH73LV-}%ruF)6Cb70Gsmk0AE diff --git a/resources/builtin/repo/servers.png b/resources/builtin/repo/servers.png index 2b9f2c3d85b52dfe01e2b29216dfea90b14cc915..749c3c1a854ec23b69dfb319b8c70fdbf7b50570 100644 GIT binary patch delta 1355 zcmV-R1+@Bz4)_X?BYy$8P)t-s_xJaYm8gi0qib`GbbFL>d6IX2mUw@cbbOSHlBKn| z#^mMb@$vHV^7HEJ?Zd{;nxL_5b&tNn%+uA|e}$ZIc#+%P;_&hEkCv&0i=pD<=j7(; z>+J5JrL}H$klEYdgo~h&m#VF@z`eoC}jcs*~ zhK-`^?eCeNud4QPn^YpK@!LPHy*4W+A z)7sF}+1lLUm!7Z7&DH4X>~40C$jj4zhMlXhzQDxIb9$4Xq_p7T=HcSzvbV&Jm8g1w znSzO*gNdJ^)!Vwg z$nEa$@9*(*dy|ovs>#gM*V*2AfR~Anr1bRlr>whugPNYBw0wh_eT18GdXkNlr_|To z&Cl1dwZeyuqV@Im_4W0Gil2&*rLeWa=;`ag!_AD7rhnk!<)*8;mYuG%xWlNfysEFg z-{9q!ov+W)*pr&9=I83Nw!?CHlI7;-Zsp|`un<>%_g$b)P~7yqly zN&o-=0FxyH5Ptvwz~4blZS|>%K9W?U=p%JW^{Ep}EV0BAODwU(DyhDqv9U?4H2U=) zFtE9~rL|40O4mDfyMYsO z7HeW;V^WgB84yM0idEXsc~NA(Sfw>C zh$0KcDy?Br>R4he9uq~Dh*jFsWl?DP3bD$V6otkoVwJISRTOCZIRD&PousfPdRm+0 zE7tUNgV$$Z!^R|yP0`)v276X7wrq_qv$h%kdbfRE{9(sVOKByIy9V#xvuFI831;O# zK`gPv%72hpVu>Y|SYE)*-rh;oXK(Zo0002kS6hAdMRrUy#y_#d5=$(x#1c!a{Ra*n z93oa4hYk;qh$Baj?G&qm<0qoSl#{uOwRGkFl^GaPpQKT{Ai6n~w^+3chA+rKoK8|W zbGG<^E>E$}MK+ElDV&d<1~xcHDW@h1T@b6B!+%kzWv5uBZ8;l7&WTmp&WkQtQ^#6) zNvzbdF8j<%A8SiX6uBZ+8CRpwm^!h_xDtgXf1JO;Z%}@V%@(OMcTwFt$lM8nJQKpJEG9%L&YlNMilzu^5v8a zd^I*n;lrNj?#P3@O*BJ449!4Ody>YsucOP&_x7w_)wf26@!uH#DyjMQyXNNRF(Kdo zU{+4!enVs9j~-Zfx+7Nh#1cy^vBdIDX{Kswt4~dnAp;Z|0001F;%5swwqA~^j$!}+ N002ovPDHLkV1hla^#K3? literal 1800 zcmeAS@N?(olHy`uVBq!ia0y~yVAKI&4rZW;-{LxV1_maU0G|+7AUC_XcNC4}5U5km zm<3D+Yf6Irf*D@@`1b$fk=D|J_LIM+n{o46%>8}A%JKR(f&C|nO3IVA?qp`&Ta|h3 zPPL71-J%W7T*9|!PH1ed>8hR7w(gOZ;%dF#@GRqQW2XS)fCEWT)WV?E!VeVf_-7}`!;c($*;cXGdp`3z0dinL={yOuC+ zn!ncgpMA^SS#v^#B(6-^!oqndooC1K??#nJ^AqN+Ijn!W!%qDY0|N`Yr;B4q1>@Vh z&1J?u60Q#~r`g@!mJ3C@PTcpfGWJYQWqteRxlozl9&L3dpkJ|qt~k$36|X6KTRL5w zZmv#J3T%xyq9nGl!&N6qup7t>o47J+ZB?(-)$D6ZVQO1nUs=0+|CRg;8w59A%Dm&^ zIm=9WTKwlKuZxRP<&w5$-CdS@aBFrxQ|XHpMpmWgYS-v#vBmn%$orbI^1ki!ja4fo zwwNVWomv=vF8OPiVMcP(mx;mgNtPy4gYA=UMtz-rxuNmMCZ0*h6_O&^PA7A0)Ny`l z*b^~L@6!uMozn%CJqpuOm)N)op1$NRx41J^(m2fT@hXASW^sPPJR5U_txqoeza-{( z*6O5y!!0v)+BMa#Z(Qbenal60?~IqWsWUHXJl~jhZkFxx2hYwKH$Kzf5T#nde=q%^ z($a`I21hl zNk(s0%<)}Ik_v9N>@@P7<|kY%mt8hJF_`P!D^uYYyH4#YoVef8X#rzcMRoQIO49x0bN%H?z&VNT6| zyvid-1QKup(>s}!4Fhi)Uwp9Zux1a6j#WGQzE@ggTsZu?w{z;n#Yd~ZPS5RMFRZ>G9VPW}5#-neXU zXKLaxy#v-ezt;Qf+|Stlbdln;waey&86-ddkT^%i4j53sLKOFBKG>Xdx$n8nwcq+{ zSBu}dF0OXLFf#A+woT`^XL@b?xLa}B_5S%@Mc<|?hDj|A)?ari{?~QcoyP>UoBulB zzVhSJvRnLpYaT*#+*E!@-qTK0ni%lS%S$;>32VLu33gn4|Mv33ga74<_kp;cu6{1- HoD!M Date: Mon, 12 Jun 2017 18:00:04 +0000 Subject: [PATCH 04/34] Add a tooltip method to PHUIIconView Summary: We seem to use these a lot. Makes the code cleaner. Test Plan: UIExamples. Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Differential Revision: https://secure.phabricator.com/D18114 --- .../uiexample/examples/PHUIIconExample.php | 3 ++- src/view/phui/PHUIIconView.php | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/applications/uiexample/examples/PHUIIconExample.php b/src/applications/uiexample/examples/PHUIIconExample.php index 35395fbff0..81778b0fd4 100644 --- a/src/applications/uiexample/examples/PHUIIconExample.php +++ b/src/applications/uiexample/examples/PHUIIconExample.php @@ -159,7 +159,8 @@ final class PHUIIconExample extends PhabricatorUIExample { ->setIcon($icon) ->setBackground('bg-blue') ->setHref('#') - ->addClass('mmr'); + ->addClass('mmr') + ->setTooltip($icon); } $layout_cicons = id(new PHUIBoxView()) diff --git a/src/view/phui/PHUIIconView.php b/src/view/phui/PHUIIconView.php index d6b1ad0ccd..8cc61ba2eb 100644 --- a/src/view/phui/PHUIIconView.php +++ b/src/view/phui/PHUIIconView.php @@ -18,6 +18,7 @@ final class PHUIIconView extends AphrontTagView { private $iconFont; private $iconColor; private $iconBackground; + private $tooltip; public function setHref($href) { $this->href = $href; @@ -60,6 +61,11 @@ final class PHUIIconView extends AphrontTagView { return $this; } + public function setTooltip($text) { + $this->tooltip = $text; + return $this; + } + protected function getTagName() { $tag = 'span'; if ($this->href) { @@ -100,11 +106,24 @@ final class PHUIIconView extends AphrontTagView { $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( 'href' => $this->href, 'style' => $style, 'aural' => false, 'class' => $classes, + 'sigil' => $sigil, + 'meta' => $meta, ); } From 0610b86f57d02c2c2ca11b5bf6cab5afbed997e8 Mon Sep 17 00:00:00 2001 From: epriestley Date: Mon, 12 Jun 2017 07:44:38 -0700 Subject: [PATCH 05/34] Allow Herald rules to apply "only the first time" to Calendar events Summary: Fixes T12821. (Some events only happen once, so the default behavior doesn't let you pick this rule, and objects must opt into it by saying "yeah, I support multiple edits".) Test Plan: Note "only the first time" selected: {F4999093} Reviewers: chad Reviewed By: chad Maniphest Tasks: T12821 Differential Revision: https://secure.phabricator.com/D18117 --- .../herald/PhabricatorCalendarEventHeraldAdapter.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/applications/calendar/herald/PhabricatorCalendarEventHeraldAdapter.php b/src/applications/calendar/herald/PhabricatorCalendarEventHeraldAdapter.php index 49d5f38959..1fc3a56317 100644 --- a/src/applications/calendar/herald/PhabricatorCalendarEventHeraldAdapter.php +++ b/src/applications/calendar/herald/PhabricatorCalendarEventHeraldAdapter.php @@ -49,6 +49,13 @@ final class PhabricatorCalendarEventHeraldAdapter extends HeraldAdapter { } } + public function getRepetitionOptions() { + return array( + HeraldRepetitionPolicyConfig::EVERY, + HeraldRepetitionPolicyConfig::FIRST, + ); + } + public function getHeraldName() { return $this->getObject()->getMonogram(); } From 4b15871ced9e66d16de04989c4ea656eff0536d0 Mon Sep 17 00:00:00 2001 From: epriestley Date: Mon, 12 Jun 2017 11:19:37 -0700 Subject: [PATCH 06/34] Fix specification of `ttl.relative` via LFS Summary: Fixes T12828. This API was tightened up D17616, but I missed this callsite. Test Plan: I've just got a good feeling in my bones. Reviewers: chad Reviewed By: chad Maniphest Tasks: T12828 Differential Revision: https://secure.phabricator.com/D18119 --- .../files/uploadsource/PhabricatorFileUploadSource.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/applications/files/uploadsource/PhabricatorFileUploadSource.php b/src/applications/files/uploadsource/PhabricatorFileUploadSource.php index cda07d590b..5e72156091 100644 --- a/src/applications/files/uploadsource/PhabricatorFileUploadSource.php +++ b/src/applications/files/uploadsource/PhabricatorFileUploadSource.php @@ -208,11 +208,17 @@ abstract class PhabricatorFileUploadSource } private function getNewFileParameters() { - return array( + $parameters = array( 'name' => $this->getName(), - 'ttl.relative' => $this->getRelativeTTL(), 'viewPolicy' => $this->getViewPolicy(), ); + + $ttl = $this->getRelativeTTL(); + if ($ttl !== null) { + $parameters['ttl.relative'] = $ttl; + } + + return $parameters; } private function getChunkEngine() { From 283a95d2aae0fd4d2b3a4c926ab18273f8b80e62 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Mon, 12 Jun 2017 11:24:17 -0700 Subject: [PATCH 07/34] Build a page for viewing all inline comments Summary: Adds a very basic list of all inline comments, threaded, and their status. Kept this a little simpler than the mock, mostly because sorting here feels a little strange given threads would be all over the place. Not sure sorted is needed in practice anyways. I'd probably lean towards just adding a JS checkbox to hide certain rows if needed in the future. Test Plan: Test various commenting structures: - Leave Comment - Update Diff - Leave new comment - Reply to comment - Reply to comment as revision author - Mark items as done - Update diff again {F4996915} Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin, epriestley Differential Revision: https://secure.phabricator.com/D18112 --- src/__phutil_library_map__.php | 4 + .../storage/PhabricatorAuditInlineComment.php | 8 + .../base/controller/PhabricatorController.php | 6 +- .../PhabricatorDifferentialApplication.php | 2 + .../DifferentialRevisionInlinesController.php | 190 ++++++++++++++++++ .../DifferentialRevisionViewController.php | 6 + .../parser/DifferentialChangesetParser.php | 65 +----- .../storage/DifferentialInlineComment.php | 7 + .../PhabricatorInlineCommentInterface.php | 3 + .../diff/view/PHUIDiffInlineThreader.php | 66 ++++++ 10 files changed, 292 insertions(+), 65 deletions(-) create mode 100644 src/applications/differential/controller/DifferentialRevisionInlinesController.php create mode 100644 src/infrastructure/diff/view/PHUIDiffInlineThreader.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index d63b99d4a2..5d917db2c0 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -547,6 +547,7 @@ phutil_register_library_map(array( 'DifferentialRevisionHeraldField' => 'applications/differential/herald/DifferentialRevisionHeraldField.php', 'DifferentialRevisionHeraldFieldGroup' => 'applications/differential/herald/DifferentialRevisionHeraldFieldGroup.php', 'DifferentialRevisionIDCommitMessageField' => 'applications/differential/field/DifferentialRevisionIDCommitMessageField.php', + 'DifferentialRevisionInlinesController' => 'applications/differential/controller/DifferentialRevisionInlinesController.php', 'DifferentialRevisionLandController' => 'applications/differential/controller/DifferentialRevisionLandController.php', 'DifferentialRevisionListController' => 'applications/differential/controller/DifferentialRevisionListController.php', 'DifferentialRevisionListView' => 'applications/differential/view/DifferentialRevisionListView.php', @@ -1738,6 +1739,7 @@ phutil_register_library_map(array( 'PHUIDiffInlineCommentTableScaffold' => 'infrastructure/diff/view/PHUIDiffInlineCommentTableScaffold.php', 'PHUIDiffInlineCommentUndoView' => 'infrastructure/diff/view/PHUIDiffInlineCommentUndoView.php', 'PHUIDiffInlineCommentView' => 'infrastructure/diff/view/PHUIDiffInlineCommentView.php', + 'PHUIDiffInlineThreader' => 'infrastructure/diff/view/PHUIDiffInlineThreader.php', 'PHUIDiffOneUpInlineCommentRowScaffold' => 'infrastructure/diff/view/PHUIDiffOneUpInlineCommentRowScaffold.php', 'PHUIDiffRevealIconView' => 'infrastructure/diff/view/PHUIDiffRevealIconView.php', 'PHUIDiffTableOfContentsItemView' => 'infrastructure/diff/view/PHUIDiffTableOfContentsItemView.php', @@ -5516,6 +5518,7 @@ phutil_register_library_map(array( 'DifferentialRevisionHeraldField' => 'HeraldField', 'DifferentialRevisionHeraldFieldGroup' => 'HeraldFieldGroup', 'DifferentialRevisionIDCommitMessageField' => 'DifferentialCommitMessageField', + 'DifferentialRevisionInlinesController' => 'DifferentialController', 'DifferentialRevisionLandController' => 'DifferentialController', 'DifferentialRevisionListController' => 'DifferentialController', 'DifferentialRevisionListView' => 'AphrontView', @@ -6872,6 +6875,7 @@ phutil_register_library_map(array( 'PHUIDiffInlineCommentTableScaffold' => 'AphrontView', 'PHUIDiffInlineCommentUndoView' => 'PHUIDiffInlineCommentView', 'PHUIDiffInlineCommentView' => 'AphrontView', + 'PHUIDiffInlineThreader' => 'Phobject', 'PHUIDiffOneUpInlineCommentRowScaffold' => 'PHUIDiffInlineCommentRowScaffold', 'PHUIDiffRevealIconView' => 'AphrontView', 'PHUIDiffTableOfContentsItemView' => 'AphrontView', diff --git a/src/applications/audit/storage/PhabricatorAuditInlineComment.php b/src/applications/audit/storage/PhabricatorAuditInlineComment.php index b330368d1b..2534384f61 100644 --- a/src/applications/audit/storage/PhabricatorAuditInlineComment.php +++ b/src/applications/audit/storage/PhabricatorAuditInlineComment.php @@ -331,6 +331,14 @@ final class PhabricatorAuditInlineComment return $this->isGhost; } + public function getDateModified() { + return $this->proxy->getDateModified(); + } + + public function getDateCreated() { + return $this->proxy->getDateCreated(); + } + /* -( PhabricatorMarkupInterface Implementation )-------------------------- */ diff --git a/src/applications/base/controller/PhabricatorController.php b/src/applications/base/controller/PhabricatorController.php index c4d1b47c40..1ecfdaf557 100644 --- a/src/applications/base/controller/PhabricatorController.php +++ b/src/applications/base/controller/PhabricatorController.php @@ -483,8 +483,10 @@ abstract class PhabricatorController extends AphrontController { // NOTE: Applications (objects of class PhabricatorApplication) can't // currently be set here, although they don't need any of the extensions // anyway. This should probably work differently than it does, though. - if ($object instanceof PhabricatorLiskDAO) { - $action_list->setObject($object); + if ($object) { + if ($object instanceof PhabricatorLiskDAO) { + $action_list->setObject($object); + } } $curtain = id(new PHUICurtainView()) diff --git a/src/applications/differential/application/PhabricatorDifferentialApplication.php b/src/applications/differential/application/PhabricatorDifferentialApplication.php index 1b6443a9e0..403e60c8a9 100644 --- a/src/applications/differential/application/PhabricatorDifferentialApplication.php +++ b/src/applications/differential/application/PhabricatorDifferentialApplication.php @@ -77,6 +77,8 @@ final class PhabricatorDifferentialApplication extends PhabricatorApplication { => 'DifferentialDiffCreateController', 'operation/(?P[1-9]\d*)/' => 'DifferentialRevisionOperationController', + 'inlines/(?P[1-9]\d*)/' + => 'DifferentialRevisionInlinesController', ), 'comment/' => array( 'preview/(?P[1-9]\d*)/' => 'DifferentialCommentPreviewController', diff --git a/src/applications/differential/controller/DifferentialRevisionInlinesController.php b/src/applications/differential/controller/DifferentialRevisionInlinesController.php new file mode 100644 index 0000000000..c5eb063e99 --- /dev/null +++ b/src/applications/differential/controller/DifferentialRevisionInlinesController.php @@ -0,0 +1,190 @@ +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); + } + +} diff --git a/src/applications/differential/controller/DifferentialRevisionViewController.php b/src/applications/differential/controller/DifferentialRevisionViewController.php index 69e45b377d..0f3675f8f6 100644 --- a/src/applications/differential/controller/DifferentialRevisionViewController.php +++ b/src/applications/differential/controller/DifferentialRevisionViewController.php @@ -574,6 +574,12 @@ final class DifferentialRevisionViewController extends DifferentialController { ->setDisabled(!$can_edit) ->setWorkflow(!$can_edit)); + $curtain->addAction( + id(new PhabricatorActionView()) + ->setIcon('fa-indent') + ->setHref("/differential/revision/inlines/{$revision_id}/") + ->setName(pht('List Inline Comments'))); + $curtain->addAction( id(new PhabricatorActionView()) ->setIcon('fa-upload') diff --git a/src/applications/differential/parser/DifferentialChangesetParser.php b/src/applications/differential/parser/DifferentialChangesetParser.php index c745d8e42a..88303cf420 100644 --- a/src/applications/differential/parser/DifferentialChangesetParser.php +++ b/src/applications/differential/parser/DifferentialChangesetParser.php @@ -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) { $final = $comment->getLineNumber() + @@ -1617,68 +1618,6 @@ final class DifferentialChangesetParser extends Phobject { 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) { if (!$map) { return null; diff --git a/src/applications/differential/storage/DifferentialInlineComment.php b/src/applications/differential/storage/DifferentialInlineComment.php index bdc231671f..cbe05663db 100644 --- a/src/applications/differential/storage/DifferentialInlineComment.php +++ b/src/applications/differential/storage/DifferentialInlineComment.php @@ -255,6 +255,13 @@ final class DifferentialInlineComment return $this; } + public function getDateModified() { + return $this->proxy->getDateModified(); + } + + public function getDateCreated() { + return $this->proxy->getDateCreated(); + } /* -( PhabricatorMarkupInterface Implementation )-------------------------- */ diff --git a/src/infrastructure/diff/interface/PhabricatorInlineCommentInterface.php b/src/infrastructure/diff/interface/PhabricatorInlineCommentInterface.php index 13bf3ad83b..5c2bafdc86 100644 --- a/src/infrastructure/diff/interface/PhabricatorInlineCommentInterface.php +++ b/src/infrastructure/diff/interface/PhabricatorInlineCommentInterface.php @@ -60,4 +60,7 @@ interface PhabricatorInlineCommentInterface extends PhabricatorMarkupInterface { public function supportsHiding(); public function isHidden(); + public function getDateModified(); + public function getDateCreated(); + } diff --git a/src/infrastructure/diff/view/PHUIDiffInlineThreader.php b/src/infrastructure/diff/view/PHUIDiffInlineThreader.php new file mode 100644 index 0000000000..5209f1f359 --- /dev/null +++ b/src/infrastructure/diff/view/PHUIDiffInlineThreader.php @@ -0,0 +1,66 @@ + $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; + } +} From df6ad07566949c2b0b590e6b890edd538ad81281 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Tue, 13 Jun 2017 11:02:12 -0700 Subject: [PATCH 08/34] Add DiffusionBranchListView for browsing branches Summary: Adds a new DiffusionBranchListView which replaces the BranchTable when browsing all branches in Diffusion. Has all the same capabilities, but is easier to read, adds a Compare button, and plays nicely on mobile. It does take up more space, but I think that's generally OK here since we expect our branches to not be heaping piles of intern revert branches. Test Plan: Follow a few repositories with branches, like Phabricator and KDE's Krita. View layouts on mobile, tablet, desktop. Try out new compare button. {F4996207} Reviewers: epriestley Reviewed By: epriestley Subscribers: avivey, Korvin Maniphest Tasks: T12824 Differential Revision: https://secure.phabricator.com/D18113 --- resources/celerity/map.php | 4 +- src/__phutil_library_map__.php | 2 + .../DiffusionBranchTableController.php | 9 +- .../view/DiffusionBranchListView.php | 149 ++++++++++++++++++ .../diffusion/view/DiffusionView.php | 4 +- .../diffusion/diffusion-history.css | 17 ++ 6 files changed, 175 insertions(+), 10 deletions(-) create mode 100644 src/applications/diffusion/view/DiffusionBranchListView.php diff --git a/resources/celerity/map.php b/resources/celerity/map.php index 2209dffea7..e5903df96e 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -71,7 +71,7 @@ return array( 'rsrc/css/application/differential/revision-history.css' => '0e8eb855', 'rsrc/css/application/differential/revision-list.css' => 'f3c47d33', 'rsrc/css/application/differential/table-of-contents.css' => 'ae4b7a55', - 'rsrc/css/application/diffusion/diffusion-history.css' => '6870e8c1', + 'rsrc/css/application/diffusion/diffusion-history.css' => '4540f568', 'rsrc/css/application/diffusion/diffusion-icons.css' => 'a6a1e2ba', 'rsrc/css/application/diffusion/diffusion-readme.css' => '419dd5b6', 'rsrc/css/application/diffusion/diffusion-source.css' => '750add59', @@ -569,7 +569,7 @@ return array( 'differential-revision-history-css' => '0e8eb855', 'differential-revision-list-css' => 'f3c47d33', 'differential-table-of-contents-css' => 'ae4b7a55', - 'diffusion-history-css' => '6870e8c1', + 'diffusion-history-css' => '4540f568', 'diffusion-icons-css' => 'a6a1e2ba', 'diffusion-readme-css' => '419dd5b6', 'diffusion-source-css' => '750add59', diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 5d917db2c0..5d88f4665c 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -613,6 +613,7 @@ phutil_register_library_map(array( 'DiffusionBlameConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionBlameConduitAPIMethod.php', 'DiffusionBlameQuery' => 'applications/diffusion/query/blame/DiffusionBlameQuery.php', 'DiffusionBlockHeraldAction' => 'applications/diffusion/herald/DiffusionBlockHeraldAction.php', + 'DiffusionBranchListView' => 'applications/diffusion/view/DiffusionBranchListView.php', 'DiffusionBranchQueryConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionBranchQueryConduitAPIMethod.php', 'DiffusionBranchTableController' => 'applications/diffusion/controller/DiffusionBranchTableController.php', 'DiffusionBranchTableView' => 'applications/diffusion/view/DiffusionBranchTableView.php', @@ -5584,6 +5585,7 @@ phutil_register_library_map(array( 'DiffusionBlameConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod', 'DiffusionBlameQuery' => 'DiffusionQuery', 'DiffusionBlockHeraldAction' => 'HeraldAction', + 'DiffusionBranchListView' => 'DiffusionView', 'DiffusionBranchQueryConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod', 'DiffusionBranchTableController' => 'DiffusionController', 'DiffusionBranchTableView' => 'DiffusionView', diff --git a/src/applications/diffusion/controller/DiffusionBranchTableController.php b/src/applications/diffusion/controller/DiffusionBranchTableController.php index e5e033f416..7f8ae11f57 100644 --- a/src/applications/diffusion/controller/DiffusionBranchTableController.php +++ b/src/applications/diffusion/controller/DiffusionBranchTableController.php @@ -48,7 +48,7 @@ final class DiffusionBranchTableController extends DiffusionController { ->withRepository($repository) ->execute(); - $table = id(new DiffusionBranchTableView()) + $list = id(new DiffusionBranchListView()) ->setUser($viewer) ->setBranches($branches) ->setCommits($commits) @@ -57,7 +57,7 @@ final class DiffusionBranchTableController extends DiffusionController { $content = id(new PHUIObjectBoxView()) ->setHeaderText($repository->getName()) ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) - ->setTable($table) + ->setTable($list) ->setPager($pager); } @@ -84,10 +84,7 @@ final class DiffusionBranchTableController extends DiffusionController { $repository->getDisplayName(), )) ->setCrumbs($crumbs) - ->appendChild( - array( - $view, - )); + ->appendChild($view); } } diff --git a/src/applications/diffusion/view/DiffusionBranchListView.php b/src/applications/diffusion/view/DiffusionBranchListView.php new file mode 100644 index 0000000000..77540bb8c3 --- /dev/null +++ b/src/applications/diffusion/view/DiffusionBranchListView.php @@ -0,0 +1,149 @@ +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) { + $status = $buildable->getBuildableStatus(); + $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); + } + } 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; + + } +} diff --git a/src/applications/diffusion/view/DiffusionView.php b/src/applications/diffusion/view/DiffusionView.php index 1d89a9dbd7..a51fbb2fd2 100644 --- a/src/applications/diffusion/view/DiffusionView.php +++ b/src/applications/diffusion/view/DiffusionView.php @@ -116,10 +116,10 @@ abstract class DiffusionView extends AphrontView { if ($button) { return id(new PHUIButtonView()) - ->setText(pht('Browse')) + ->setTag('a') ->setIcon('fa-code') ->setHref($href) - ->setTag('a') + ->setToolTip(pht('Browse')) ->setButtonType(PHUIButtonView::BUTTONTYPE_SIMPLE); } diff --git a/webroot/rsrc/css/application/diffusion/diffusion-history.css b/webroot/rsrc/css/application/diffusion/diffusion-history.css index 2d0aea3b10..f4a51f7b56 100644 --- a/webroot/rsrc/css/application/diffusion/diffusion-history.css +++ b/webroot/rsrc/css/application/diffusion/diffusion-history.css @@ -30,6 +30,23 @@ margin-left: 4px; } +/* - Branch Styles ----------------------------------------------------------*/ + +.diffusion-branch-list .phui-oi-attribute a { + color: {$darkbluetext}; +} + +.diffusion-branch-list .phui-oi-attribute-spacer { + visibility: hidden; +} + +.diffusion-branch-list .phui-oi-subhead { + color: {$bluetext}; +} + +.diffusion-branch-list .phui-oi-subhead .phui-tag-view { + margin-right: 4px; +} /* - Phone Style ------------------------------------------------------------*/ From 6f7b31fbf8a57d1eb8e95a5d774ab7f4a6a9eb95 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Tue, 13 Jun 2017 11:16:57 -0700 Subject: [PATCH 09/34] Add a DiffusionTagListView Summary: Moves DiffusionTagsListView to uhhh, list. Separates out table view which is still in use now, implements mobile friendly UI for tags. Test Plan: Review KDE's Krita repository locally with lots of tags, desktop and mobile. {F4997708} Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Maniphest Tasks: T12824 Differential Revision: https://secure.phabricator.com/D18115 --- src/__phutil_library_map__.php | 2 + .../DiffusionRepositoryController.php | 2 +- .../controller/DiffusionTagListController.php | 25 ++-- .../view/DiffusionBranchListView.php | 13 +- .../view/DiffusionHistoryListView.php | 14 +- .../diffusion/view/DiffusionTagListView.php | 138 +++++++++-------- .../diffusion/view/DiffusionTagTableView.php | 140 ++++++++++++++++++ .../diffusion/view/DiffusionView.php | 15 +- 8 files changed, 246 insertions(+), 103 deletions(-) create mode 100644 src/applications/diffusion/view/DiffusionTagTableView.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 5d88f4665c..9ed3195e0b 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -892,6 +892,7 @@ phutil_register_library_map(array( 'DiffusionSymbolQuery' => 'applications/diffusion/query/DiffusionSymbolQuery.php', 'DiffusionTagListController' => 'applications/diffusion/controller/DiffusionTagListController.php', 'DiffusionTagListView' => 'applications/diffusion/view/DiffusionTagListView.php', + 'DiffusionTagTableView' => 'applications/diffusion/view/DiffusionTagTableView.php', 'DiffusionTaggedRepositoriesFunctionDatasource' => 'applications/diffusion/typeahead/DiffusionTaggedRepositoriesFunctionDatasource.php', 'DiffusionTagsQueryConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionTagsQueryConduitAPIMethod.php', 'DiffusionURIEditConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionURIEditConduitAPIMethod.php', @@ -5866,6 +5867,7 @@ phutil_register_library_map(array( 'DiffusionSymbolQuery' => 'PhabricatorOffsetPagedQuery', 'DiffusionTagListController' => 'DiffusionController', 'DiffusionTagListView' => 'DiffusionView', + 'DiffusionTagTableView' => 'DiffusionView', 'DiffusionTaggedRepositoriesFunctionDatasource' => 'PhabricatorTypeaheadCompositeDatasource', 'DiffusionTagsQueryConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod', 'DiffusionURIEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod', diff --git a/src/applications/diffusion/controller/DiffusionRepositoryController.php b/src/applications/diffusion/controller/DiffusionRepositoryController.php index 72b4d105d2..e341b87972 100644 --- a/src/applications/diffusion/controller/DiffusionRepositoryController.php +++ b/src/applications/diffusion/controller/DiffusionRepositoryController.php @@ -492,7 +492,7 @@ final class DiffusionRepositoryController extends DiffusionController { ->needCommitData(true) ->execute(); - $view = id(new DiffusionTagListView()) + $view = id(new DiffusionTagTableView()) ->setUser($viewer) ->setDiffusionRequest($drequest) ->setTags($tags) diff --git a/src/applications/diffusion/controller/DiffusionTagListController.php b/src/applications/diffusion/controller/DiffusionTagListController.php index df3b356f5d..5e765ddcb6 100644 --- a/src/applications/diffusion/controller/DiffusionTagListController.php +++ b/src/applications/diffusion/controller/DiffusionTagListController.php @@ -64,17 +64,21 @@ final class DiffusionTagListController extends DiffusionController { ->needCommitData(true) ->execute(); - $view = id(new DiffusionTagListView()) + $tag_list = id(new DiffusionTagListView()) ->setTags($tags) ->setUser($viewer) ->setCommits($commits) ->setDiffusionRequest($drequest); - $phids = $view->getRequiredHandlePHIDs(); + $phids = $tag_list->getRequiredHandlePHIDs(); $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( @@ -84,17 +88,9 @@ final class DiffusionTagListController extends DiffusionController { )); $crumbs->setBorder(true); - $box = id(new PHUIObjectBoxView()) - ->setHeaderText($repository->getDisplayName()) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) - ->setTable($view) - ->setPager($pager); - $view = id(new PHUITwoColumnView()) ->setHeader($header) - ->setFooter(array( - $box, - )); + ->setFooter($content); return $this->newPage() ->setTitle( @@ -103,7 +99,8 @@ final class DiffusionTagListController extends DiffusionController { $repository->getDisplayName(), )) ->setCrumbs($crumbs) - ->appendChild($view); + ->appendChild($view) + ->addClass('diffusion-history-view'); } } diff --git a/src/applications/diffusion/view/DiffusionBranchListView.php b/src/applications/diffusion/view/DiffusionBranchListView.php index 77540bb8c3..8d1df82dc9 100644 --- a/src/applications/diffusion/view/DiffusionBranchListView.php +++ b/src/applications/diffusion/view/DiffusionBranchListView.php @@ -48,18 +48,7 @@ final class DiffusionBranchListView extends DiffusionView { $buildable = idx($buildables, $commit->getPHID()); if ($buildable) { - $status = $buildable->getBuildableStatus(); - $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); + $build_view = $this->renderBuildable($buildable, 'button'); } } else { $datetime = null; diff --git a/src/applications/diffusion/view/DiffusionHistoryListView.php b/src/applications/diffusion/view/DiffusionHistoryListView.php index 9d6727a357..9dfa46cbef 100644 --- a/src/applications/diffusion/view/DiffusionHistoryListView.php +++ b/src/applications/diffusion/view/DiffusionHistoryListView.php @@ -119,19 +119,7 @@ final class DiffusionHistoryListView extends DiffusionHistoryView { if ($show_builds) { $buildable = idx($buildables, $commit->getPHID()); if ($buildable !== null) { - $status = $buildable->getBuildableStatus(); - $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'); + $build_view = $this->renderBuildable($buildable, 'button'); } } diff --git a/src/applications/diffusion/view/DiffusionTagListView.php b/src/applications/diffusion/view/DiffusionTagListView.php index df59925522..f9030581e3 100644 --- a/src/applications/diffusion/view/DiffusionTagListView.php +++ b/src/applications/diffusion/view/DiffusionTagListView.php @@ -29,36 +29,28 @@ final class DiffusionTagListView extends DiffusionView { $drequest = $this->getDiffusionRequest(); $repository = $drequest->getRepository(); $viewer = $this->getViewer(); + require_celerity_resource('diffusion-history-css'); $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) { $commit = idx($this->commits, $tag->getCommitIdentifier()); + $button_bar = new PHUIButtonBarView(); - $tag_link = phutil_tag( - 'a', + $tag_href = $drequest->generateURI( array( - 'href' => $drequest->generateURI( - array( - 'action' => 'browse', - 'commit' => $tag->getName(), - )), - ), - $tag->getName()); + 'action' => 'history', + 'commit' => $tag->getName(), + )); - $commit_link = phutil_tag( - 'a', + $commit_href = $drequest->generateURI( array( - 'href' => $drequest->generateURI( - array( - 'action' => 'commit', - 'commit' => $tag->getCommitIdentifier(), - )), - ), - $repository->formatCommitName( - $tag->getCommitIdentifier())); + 'action' => 'commit', + 'commit' => $tag->getCommitIdentifier(), + )); $author = null; if ($commit && $commit->getAuthorPHID()) { @@ -69,6 +61,15 @@ final class DiffusionTagListView extends DiffusionView { $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; if ($tag->getType() == 'git/tag') { // 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) { $buildable = idx($buildables, $commit->getPHID()); if ($buildable) { - $build = $this->renderBuildable($buildable); - $has_builds = true; + $build_view = $this->renderBuildable($buildable, 'button'); } } - $history = $this->linkTagHistory($tag->getName()); + if ($repository->supportsBranchComparison()) { + $compare_uri = $drequest->generateURI( + array( + 'action' => 'compare', + 'head' => $tag->getName(), + )); - $rows[] = array( - $history, - $tag_link, - $commit_link, - $build, - $author, - $description, - $viewer->formatShortDateTime($tag->getEpoch()), - ); - } + $button_bar->addButton( + id(new PHUIButtonView()) + ->setTag('a') + ->setIcon('fa-balance-scale') + ->setToolTip(pht('Compare')) + ->setButtonType(PHUIButtonView::BUTTONTYPE_SIMPLE) + ->setWorkflow(true) + ->setHref($compare_uri)); + } - $table = id(new AphrontTableView($rows)) - ->setHeaders( + $commit_name = $repository->formatCommitName( + $tag->getCommitIdentifier(), $local = true); + + $browse_href = $drequest->generateURI( 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, + 'action' => 'browse', + 'commit' => $tag->getName(), )); - return $table->render(); + $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; } } diff --git a/src/applications/diffusion/view/DiffusionTagTableView.php b/src/applications/diffusion/view/DiffusionTagTableView.php new file mode 100644 index 0000000000..59a06353ab --- /dev/null +++ b/src/applications/diffusion/view/DiffusionTagTableView.php @@ -0,0 +1,140 @@ +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(); + } + +} diff --git a/src/applications/diffusion/view/DiffusionView.php b/src/applications/diffusion/view/DiffusionView.php index a51fbb2fd2..d058dc5cec 100644 --- a/src/applications/diffusion/view/DiffusionView.php +++ b/src/applications/diffusion/view/DiffusionView.php @@ -190,7 +190,8 @@ abstract class DiffusionView extends AphrontView { } final protected function renderBuildable( - HarbormasterBuildable $buildable) { + HarbormasterBuildable $buildable, + $type = null) { $status = $buildable->getBuildableStatus(); Javelin::initBehavior('phabricator-tooltips'); @@ -198,6 +199,18 @@ abstract class DiffusionView extends AphrontView { $color = HarbormasterBuildable::getBuildableStatusColor($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()) ->setIcon($icon.' '.$color) ->addSigil('has-tooltip') From 21d16c723613b9612bb13cda4827e981c9dcb6b2 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Tue, 13 Jun 2017 10:03:28 -0700 Subject: [PATCH 10/34] Fix cancel button on inline comment view Summary: Switch over to PHUIButtonView Test Plan: Cancel, Edit, Submit new inline diff comment. Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Differential Revision: https://secure.phabricator.com/D18120 --- .../diff/view/PHUIDiffInlineCommentEditView.php | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/infrastructure/diff/view/PHUIDiffInlineCommentEditView.php b/src/infrastructure/diff/view/PHUIDiffInlineCommentEditView.php index a7c10b5b48..7ad3b1f1a6 100644 --- a/src/infrastructure/diff/view/PHUIDiffInlineCommentEditView.php +++ b/src/infrastructure/diff/view/PHUIDiffInlineCommentEditView.php @@ -121,14 +121,13 @@ final class PHUIDiffInlineCommentEditView private function renderBody() { $buttons = array(); - $buttons[] = phutil_tag('button', array(), pht('Save Draft')); - $buttons[] = javelin_tag( - 'button', - array( - 'sigil' => 'inline-edit-cancel', - 'class' => 'grey', - ), - pht('Cancel')); + $buttons[] = id(new PHUIButtonView()) + ->setText(pht('Save Draft')); + + $buttons[] = id(new PHUIButtonView()) + ->setText(pht('Cancel')) + ->setColor(PHUIButtonView::GREY) + ->addSigil('inline-edit-cancel'); $title = phutil_tag( 'div', From e1850b3c4e4efec5d8c4a3b9423ba0f3a8d65ece Mon Sep 17 00:00:00 2001 From: Mukunda Modell Date: Mon, 12 Jun 2017 11:00:39 -0500 Subject: [PATCH 11/34] Allow dashboard panels to be found by monogram Summary: Just add the monogram to the datasource's `name` field so that it will match when typing Wnn in the typeahead field. Test Plan: Tested locally on my dev phab. Try searching for a panel by monogram in the 'Add existing panel' dialog on the 'arrange workboard' interface. Previously: typing W123 showed no results. After this change: typing W123 finds the panel W123 Reviewers: chad, epriestley, #blessed_reviewers Reviewed By: epriestley, #blessed_reviewers Subscribers: Korvin Differential Revision: https://secure.phabricator.com/D18121 --- .../typeahead/PhabricatorDashboardPanelDatasource.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/applications/dashboard/typeahead/PhabricatorDashboardPanelDatasource.php b/src/applications/dashboard/typeahead/PhabricatorDashboardPanelDatasource.php index 958883d34e..d534d32adc 100644 --- a/src/applications/dashboard/typeahead/PhabricatorDashboardPanelDatasource.php +++ b/src/applications/dashboard/typeahead/PhabricatorDashboardPanelDatasource.php @@ -42,8 +42,7 @@ final class PhabricatorDashboardPanelDatasource $properties = $panel->getProperties(); $result = id(new PhabricatorTypeaheadResult()) - ->setName($panel->getName()) - ->setDisplayName($monogram.' '.$panel->getName()) + ->setName($monogram.' '.$panel->getName()) ->setPHID($id) ->setIcon($impl->getIcon()) ->addAttribute($type_text); From 3d70db9eb5d052a8eff5b7c8f5e85b19e12a72cd Mon Sep 17 00:00:00 2001 From: epriestley Date: Wed, 14 Jun 2017 12:10:39 -0700 Subject: [PATCH 12/34] Queue a worker task to send mail only after committing the mail transaction Summary: Fixes T12844. This code is misleading: the daemon insert is happening on a different connection, and is not inside the transaction on the Mail connection. What actually happens is this: - (Connection A) `BEGIN` - (Connection A) `INSERT INTO mail ...` - (Connection B) `INSERT INTO worker ...` <-- This is a different connection, and it is NOT in a transaction! - There's a race window here: the worker row is globally visible but the mail row is still isolated inside the transaction. - (Connection A) `COMMIT` - Now we're clear: the mail row is globally visible. Change this code to reflect what's actually happening. This means that if the worker row insert fails for some reason, we'll now throw with a mail row written to the database. But this is fine: it doesn't send on its own (so it can't cause mail loops or anything) and it can be re-queued with `bin/mail resend` if necessary without too much trouble. Test Plan: See T12844 for particulars. Made some comments on tasks, saw the daemons send mail. Reviewers: chad, amckinley, jmeador Reviewed By: jmeador Maniphest Tasks: T12844 Differential Revision: https://secure.phabricator.com/D18124 --- .../metamta/storage/PhabricatorMetaMTAMail.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/applications/metamta/storage/PhabricatorMetaMTAMail.php b/src/applications/metamta/storage/PhabricatorMetaMTAMail.php index f2ed8c7721..20b1482036 100644 --- a/src/applications/metamta/storage/PhabricatorMetaMTAMail.php +++ b/src/applications/metamta/storage/PhabricatorMetaMTAMail.php @@ -372,16 +372,16 @@ final class PhabricatorMetaMTAMail } $editor->save(); - // Queue a task to send this mail. - $mailer_task = PhabricatorWorker::scheduleTask( - 'PhabricatorMetaMTAWorker', - $this->getID(), - array( - 'priority' => PhabricatorWorker::PRIORITY_ALERTS, - )); - $this->saveTransaction(); + // Queue a task to send this mail. + $mailer_task = PhabricatorWorker::scheduleTask( + 'PhabricatorMetaMTAWorker', + $this->getID(), + array( + 'priority' => PhabricatorWorker::PRIORITY_ALERTS, + )); + return $result; } From 8008ade9af46d417aec187f4213118d220077b32 Mon Sep 17 00:00:00 2001 From: Austin McKinley Date: Wed, 14 Jun 2017 14:42:14 -0700 Subject: [PATCH 13/34] Use keywords instead of ints to update task priority in ManiphestEditEngine Summary: Fixes T12124. Changes `ManiphestEditEngine` to populate the select using priority keywords instead of the integer value. Marks `maniphest.querystatuses` as frozen. Adds a new Conduit method for fetching potential task statuses. Test Plan: Created tasks and changed their priorities, observed that transactions in the DB still have the same type (integers as strings). Invoked `maniphest.update` with `priority => '90'` and observed that it still works. Invoked `maniphest.edit` with `priority => 'unbreak'` and observed that it now works. Reviewers: #blessed_reviewers, epriestley Reviewed By: #blessed_reviewers, epriestley Subscribers: Korvin, epriestley Maniphest Tasks: T12124 Differential Revision: https://secure.phabricator.com/D18111 --- .../sql/autopatches/20170614.taskstatus.sql | 4 ++ src/__phutil_library_map__.php | 2 + .../__tests__/ManiphestTaskTestCase.php | 10 +++- .../bulk/ManiphestTaskEditBulkJobType.php | 5 ++ .../command/ManiphestPriorityEmailCommand.php | 16 ++---- .../conduit/ManiphestConduitAPIMethod.php | 4 +- ...ManiphestQueryStatusesConduitAPIMethod.php | 10 ++++ .../ManiphestStatusSearchConduitAPIMethod.php | 52 +++++++++++++++++++ .../constants/ManiphestTaskPriority.php | 43 ++++++++++++++- .../constants/ManiphestTaskStatus.php | 14 ++--- .../__tests__/ManiphestTaskStatusTestCase.php | 9 +++- .../ManiphestSubpriorityController.php | 5 +- .../maniphest/editor/ManiphestEditEngine.php | 32 ++++++------ .../ManiphestTaskPriorityHeraldAction.php | 7 ++- ...bricatorManiphestTaskTestDataGenerator.php | 5 +- .../maniphest/storage/ManiphestTask.php | 10 +++- .../ManiphestTaskPriorityTransaction.php | 13 +++++ .../PhabricatorProjectMoveController.php | 5 +- 18 files changed, 198 insertions(+), 48 deletions(-) create mode 100644 resources/sql/autopatches/20170614.taskstatus.sql create mode 100644 src/applications/maniphest/conduit/ManiphestStatusSearchConduitAPIMethod.php diff --git a/resources/sql/autopatches/20170614.taskstatus.sql b/resources/sql/autopatches/20170614.taskstatus.sql new file mode 100644 index 0000000000..2543632093 --- /dev/null +++ b/resources/sql/autopatches/20170614.taskstatus.sql @@ -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; diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 9ed3195e0b..bca514a06e 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1507,6 +1507,7 @@ phutil_register_library_map(array( 'ManiphestSearchConduitAPIMethod' => 'applications/maniphest/conduit/ManiphestSearchConduitAPIMethod.php', 'ManiphestStatusConfigOptionType' => 'applications/maniphest/config/ManiphestStatusConfigOptionType.php', 'ManiphestStatusEmailCommand' => 'applications/maniphest/command/ManiphestStatusEmailCommand.php', + 'ManiphestStatusSearchConduitAPIMethod' => 'applications/maniphest/conduit/ManiphestStatusSearchConduitAPIMethod.php', 'ManiphestSubpriorityController' => 'applications/maniphest/controller/ManiphestSubpriorityController.php', 'ManiphestSubtypesConfigOptionsType' => 'applications/maniphest/config/ManiphestSubtypesConfigOptionsType.php', 'ManiphestTask' => 'applications/maniphest/storage/ManiphestTask.php', @@ -6607,6 +6608,7 @@ phutil_register_library_map(array( 'ManiphestSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod', 'ManiphestStatusConfigOptionType' => 'PhabricatorConfigJSONOptionType', 'ManiphestStatusEmailCommand' => 'ManiphestEmailCommand', + 'ManiphestStatusSearchConduitAPIMethod' => 'ManiphestConduitAPIMethod', 'ManiphestSubpriorityController' => 'ManiphestController', 'ManiphestSubtypesConfigOptionsType' => 'PhabricatorConfigJSONOptionType', 'ManiphestTask' => array( diff --git a/src/applications/maniphest/__tests__/ManiphestTaskTestCase.php b/src/applications/maniphest/__tests__/ManiphestTaskTestCase.php index 1e571190d7..58190f6a89 100644 --- a/src/applications/maniphest/__tests__/ManiphestTaskTestCase.php +++ b/src/applications/maniphest/__tests__/ManiphestTaskTestCase.php @@ -194,11 +194,14 @@ final class ManiphestTaskTestCase extends PhabricatorTestCase { $dst, $is_after); + $keyword_map = ManiphestTaskPriority::getTaskPriorityKeywordsMap(); + $keyword = head($keyword_map[$pri]); + $xactions = array(); $xactions[] = id(new ManiphestTransaction()) ->setTransactionType(ManiphestTaskPriorityTransaction::TRANSACTIONTYPE) - ->setNewValue($pri); + ->setNewValue($keyword); $xactions[] = id(new ManiphestTransaction()) ->setTransactionType(ManiphestTaskSubpriorityTransaction::TRANSACTIONTYPE) @@ -217,11 +220,14 @@ final class ManiphestTaskTestCase extends PhabricatorTestCase { $target_priority, $is_end); + $keyword_map = ManiphestTaskPriority::getTaskPriorityKeywordsMap(); + $keyword = head($keyword_map[$pri]); + $xactions = array(); $xactions[] = id(new ManiphestTransaction()) ->setTransactionType(ManiphestTaskPriorityTransaction::TRANSACTIONTYPE) - ->setNewValue($pri); + ->setNewValue($keyword); $xactions[] = id(new ManiphestTransaction()) ->setTransactionType(ManiphestTaskSubpriorityTransaction::TRANSACTIONTYPE) diff --git a/src/applications/maniphest/bulk/ManiphestTaskEditBulkJobType.php b/src/applications/maniphest/bulk/ManiphestTaskEditBulkJobType.php index 0e11530b51..1b083d88f9 100644 --- a/src/applications/maniphest/bulk/ManiphestTaskEditBulkJobType.php +++ b/src/applications/maniphest/bulk/ManiphestTaskEditBulkJobType.php @@ -285,6 +285,11 @@ final class ManiphestTaskEditBulkJobType '=' => array_fuse($value), )); break; + case ManiphestTaskPriorityTransaction::TRANSACTIONTYPE: + $keyword_map = ManiphestTaskPriority::getTaskPriorityKeywordsMap(); + $keyword = head(idx($keyword_map, $value)); + $xaction->setNewValue($keyword); + break; default: $xaction->setNewValue($value); break; diff --git a/src/applications/maniphest/command/ManiphestPriorityEmailCommand.php b/src/applications/maniphest/command/ManiphestPriorityEmailCommand.php index 5d7bbb1eea..ef966a50da 100644 --- a/src/applications/maniphest/command/ManiphestPriorityEmailCommand.php +++ b/src/applications/maniphest/command/ManiphestPriorityEmailCommand.php @@ -49,18 +49,8 @@ final class ManiphestPriorityEmailCommand array $argv) { $xactions = array(); - $target = phutil_utf8_strtolower(head($argv)); - $priority = null; - - $keywords = ManiphestTaskPriority::getTaskPriorityKeywordsMap(); - foreach ($keywords as $key => $words) { - foreach ($words as $word) { - if ($word == $target) { - $priority = $key; - break; - } - } - } + $keyword = phutil_utf8_strtolower(head($argv)); + $priority = ManiphestTaskPriority::getTaskPriorityFromKeyword($keyword); if ($priority === null) { return array(); @@ -72,7 +62,7 @@ final class ManiphestPriorityEmailCommand $xactions[] = $object->getApplicationTransactionTemplate() ->setTransactionType(ManiphestTaskPriorityTransaction::TRANSACTIONTYPE) - ->setNewValue($priority); + ->setNewValue($keyword); return $xactions; } diff --git a/src/applications/maniphest/conduit/ManiphestConduitAPIMethod.php b/src/applications/maniphest/conduit/ManiphestConduitAPIMethod.php index 5a6a8cea33..640e30fee5 100644 --- a/src/applications/maniphest/conduit/ManiphestConduitAPIMethod.php +++ b/src/applications/maniphest/conduit/ManiphestConduitAPIMethod.php @@ -99,7 +99,9 @@ abstract class ManiphestConduitAPIMethod extends ConduitAPIMethod { throw id(new ConduitException('ERR-INVALID-PARAMETER')) ->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'); diff --git a/src/applications/maniphest/conduit/ManiphestQueryStatusesConduitAPIMethod.php b/src/applications/maniphest/conduit/ManiphestQueryStatusesConduitAPIMethod.php index 971be8820b..28afaa4fe1 100644 --- a/src/applications/maniphest/conduit/ManiphestQueryStatusesConduitAPIMethod.php +++ b/src/applications/maniphest/conduit/ManiphestQueryStatusesConduitAPIMethod.php @@ -33,4 +33,14 @@ final class ManiphestQueryStatusesConduitAPIMethod 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.'); + } + } diff --git a/src/applications/maniphest/conduit/ManiphestStatusSearchConduitAPIMethod.php b/src/applications/maniphest/conduit/ManiphestStatusSearchConduitAPIMethod.php new file mode 100644 index 0000000000..7185cde96f --- /dev/null +++ b/src/applications/maniphest/conduit/ManiphestStatusSearchConduitAPIMethod.php @@ -0,0 +1,52 @@ +'; + } + + 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); + } + +} diff --git a/src/applications/maniphest/constants/ManiphestTaskPriority.php b/src/applications/maniphest/constants/ManiphestTaskPriority.php index dd2ab69c69..8bc682f7e4 100644 --- a/src/applications/maniphest/constants/ManiphestTaskPriority.php +++ b/src/applications/maniphest/constants/ManiphestTaskPriority.php @@ -2,6 +2,8 @@ final class ManiphestTaskPriority extends ManiphestConstants { + const UNKNOWN_PRIORITY_KEYWORD = '!!unknown!!'; + /** * Get the priorities and their full descriptions. * @@ -105,6 +107,18 @@ final class ManiphestTaskPriority extends ManiphestConstants { 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) { $config = idx(self::getConfig(), $priority, array()); return idx($config, 'disabled', false); @@ -116,6 +130,18 @@ final class ManiphestTaskPriority extends ManiphestConstants { 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) { if (!is_array($config)) { throw new Exception( @@ -147,9 +173,24 @@ final class ManiphestTaskPriority extends ManiphestConstants { 'name' => 'string', 'short' => 'optional string', 'color' => 'optional string', - 'keywords' => 'optional list', + 'keywords' => 'list', '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')); + } + } } } diff --git a/src/applications/maniphest/constants/ManiphestTaskStatus.php b/src/applications/maniphest/constants/ManiphestTaskStatus.php index 6781fb7724..53d2e1afe3 100644 --- a/src/applications/maniphest/constants/ManiphestTaskStatus.php +++ b/src/applications/maniphest/constants/ManiphestTaskStatus.php @@ -232,16 +232,17 @@ final class ManiphestTaskStatus extends ManiphestConstants { * @task validate */ public static function isValidStatusConstant($constant) { - if (strlen($constant) > 12) { + if (!strlen($constant) || strlen($constant) > 64) { 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 true; } - /** * @task validate */ @@ -250,10 +251,9 @@ final class ManiphestTaskStatus extends ManiphestConstants { if (!self::isValidStatusConstant($key)) { throw new Exception( pht( - 'Key "%s" is not a valid status constant. Status constants must '. - 'be 1-12 characters long and contain only lowercase letters (a-z) '. - 'and digits (0-9). For example, "%s" or "%s" are reasonable '. - 'choices.', + 'Key "%s" is not a valid status constant. Status constants '. + 'must be 1-64 alphanumeric characters and cannot be exclusively '. + 'digits. For example, "%s" or "%s" are reasonable choices.', $key, 'open', 'closed')); diff --git a/src/applications/maniphest/constants/__tests__/ManiphestTaskStatusTestCase.php b/src/applications/maniphest/constants/__tests__/ManiphestTaskStatusTestCase.php index 20f4c438a7..140c86d6dd 100644 --- a/src/applications/maniphest/constants/__tests__/ManiphestTaskStatusTestCase.php +++ b/src/applications/maniphest/constants/__tests__/ManiphestTaskStatusTestCase.php @@ -10,10 +10,15 @@ final class ManiphestTaskStatusTestCase extends PhabricatorTestCase { 'duplicate2' => true, '' => false, - 'longlonglonglong' => false, + 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' => + false, '.' => false, - 'ABCD' => false, + ' ' => false, + 'ABCD' => true, 'a b c ' => false, + '1' => false, + '111' => false, + '11a' => true, ); foreach ($map as $input => $expect) { diff --git a/src/applications/maniphest/controller/ManiphestSubpriorityController.php b/src/applications/maniphest/controller/ManiphestSubpriorityController.php index e91cc65d4a..8869b6a327 100644 --- a/src/applications/maniphest/controller/ManiphestSubpriorityController.php +++ b/src/applications/maniphest/controller/ManiphestSubpriorityController.php @@ -40,11 +40,14 @@ final class ManiphestSubpriorityController extends ManiphestController { $is_end = false); } + $keyword_map = ManiphestTaskPriority::getTaskPriorityKeywordsMap(); + $keyword = head(idx($keyword_map, $pri)); + $xactions = array(); $xactions[] = id(new ManiphestTransaction()) ->setTransactionType(ManiphestTaskPriorityTransaction::TRANSACTIONTYPE) - ->setNewValue($pri); + ->setNewValue($keyword); $xactions[] = id(new ManiphestTransaction()) ->setTransactionType(ManiphestTaskSubpriorityTransaction::TRANSACTIONTYPE) diff --git a/src/applications/maniphest/editor/ManiphestEditEngine.php b/src/applications/maniphest/editor/ManiphestEditEngine.php index 52491ce6e6..acd27fc908 100644 --- a/src/applications/maniphest/editor/ManiphestEditEngine.php +++ b/src/applications/maniphest/editor/ManiphestEditEngine.php @@ -215,7 +215,7 @@ EODOCS ->setConduitTypeDescription(pht('New task priority constant.')) ->setTransactionType(ManiphestTaskPriorityTransaction::TRANSACTIONTYPE) ->setIsCopyable(true) - ->setValue($object->getPriority()) + ->setValue($object->getPriorityKeyword()) ->setOptions($priority_map) ->setCommentActionLabel(pht('Change Priority')), ); @@ -289,29 +289,29 @@ EODOCS private function getTaskPriorityMap(ManiphestTask $task) { $priority_map = ManiphestTaskPriority::getTaskPriorityMap(); + $priority_keywords = ManiphestTaskPriority::getTaskPriorityKeywordsMap(); $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 - // 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) { - $priority_map[$current_priority] = pht( + $results[ManiphestTaskPriority::UNKNOWN_PRIORITY_KEYWORD] = pht( '', $current_priority); } - foreach ($priority_map as $priority => $priority_name) { - // Always keep the current priority. - if ($priority == $current_priority) { - continue; - } - - if (ManiphestTaskPriority::isDisabledPriority($priority)) { - unset($priority_map[$priority]); - continue; - } - } - - return $priority_map; + return $results; } protected function newEditResponse( diff --git a/src/applications/maniphest/herald/ManiphestTaskPriorityHeraldAction.php b/src/applications/maniphest/herald/ManiphestTaskPriorityHeraldAction.php index ff8420544d..2e2db4b62d 100644 --- a/src/applications/maniphest/herald/ManiphestTaskPriorityHeraldAction.php +++ b/src/applications/maniphest/herald/ManiphestTaskPriorityHeraldAction.php @@ -39,12 +39,15 @@ final class ManiphestTaskPriorityHeraldAction return; } + $keyword_map = ManiphestTaskPriority::getTaskPriorityKeywordsMap(); + $keyword = head(idx($keyword_map, $priority)); + $xaction = $adapter->newTransaction() ->setTransactionType(ManiphestTaskPriorityTransaction::TRANSACTIONTYPE) - ->setNewValue($priority); + ->setNewValue($keyword); $adapter->queueTransaction($xaction); - $this->logEffect(self::DO_PRIORITY, $priority); + $this->logEffect(self::DO_PRIORITY, $keyword); } public function getHeraldActionStandardType() { diff --git a/src/applications/maniphest/lipsum/PhabricatorManiphestTaskTestDataGenerator.php b/src/applications/maniphest/lipsum/PhabricatorManiphestTaskTestDataGenerator.php index 2d6a6807ce..3fc1957b4f 100644 --- a/src/applications/maniphest/lipsum/PhabricatorManiphestTaskTestDataGenerator.php +++ b/src/applications/maniphest/lipsum/PhabricatorManiphestTaskTestDataGenerator.php @@ -100,7 +100,10 @@ final class PhabricatorManiphestTaskTestDataGenerator } 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() { diff --git a/src/applications/maniphest/storage/ManiphestTask.php b/src/applications/maniphest/storage/ManiphestTask.php index 7cf9d3353f..3b312fc9cc 100644 --- a/src/applications/maniphest/storage/ManiphestTask.php +++ b/src/applications/maniphest/storage/ManiphestTask.php @@ -79,7 +79,7 @@ final class ManiphestTask extends ManiphestDAO ), self::CONFIG_COLUMN_SCHEMA => array( 'ownerPHID' => 'phid?', - 'status' => 'text12', + 'status' => 'text64', 'priority' => 'uint32', 'title' => 'sort', 'originalTitle' => 'text', @@ -245,6 +245,14 @@ final class ManiphestTask extends ManiphestDAO ); } + public function getPriorityKeyword() { + $priority = $this->getPriority(); + $map = ManiphestTaskPriority::getTaskPriorityKeywordsMap(); + $default = array(ManiphestTaskPriority::UNKNOWN_PRIORITY_KEYWORD); + $keywords = idx($map, $priority, $default); + return head($keywords); + } + private function comparePriorityTo(ManiphestTask $other) { $upri = $this->getPriority(); $vpri = $other->getPriority(); diff --git a/src/applications/maniphest/xaction/ManiphestTaskPriorityTransaction.php b/src/applications/maniphest/xaction/ManiphestTaskPriorityTransaction.php index f7d58911ba..4e505668d1 100644 --- a/src/applications/maniphest/xaction/ManiphestTaskPriorityTransaction.php +++ b/src/applications/maniphest/xaction/ManiphestTaskPriorityTransaction.php @@ -12,6 +12,19 @@ final class ManiphestTaskPriorityTransaction 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) { $object->setPriority($value); } diff --git a/src/applications/project/controller/PhabricatorProjectMoveController.php b/src/applications/project/controller/PhabricatorProjectMoveController.php index 801acbb90e..29b70cfafc 100644 --- a/src/applications/project/controller/PhabricatorProjectMoveController.php +++ b/src/applications/project/controller/PhabricatorProjectMoveController.php @@ -153,11 +153,14 @@ final class PhabricatorProjectMoveController break; } + $keyword_map = ManiphestTaskPriority::getTaskPriorityKeywordsMap(); + $keyword = head(idx($keyword_map, $pri)); + $xactions = array(); if ($pri !== null) { $xactions[] = id(new ManiphestTransaction()) ->setTransactionType(ManiphestTaskPriorityTransaction::TRANSACTIONTYPE) - ->setNewValue($pri); + ->setNewValue($keyword); $xactions[] = id(new ManiphestTransaction()) ->setTransactionType( ManiphestTaskSubpriorityTransaction::TRANSACTIONTYPE) From 887bd2d66ef078c73a08e81e4160921ee127a678 Mon Sep 17 00:00:00 2001 From: epriestley Date: Thu, 15 Jun 2017 04:17:01 -0700 Subject: [PATCH 14/34] In the UI, rename "Hide Inline" to "Collapse Inline" Summary: Ref T12733. This paves the way for a separate "hide" operation which completely hides things. (I didn't extend this to the server side because that would require schema changes and the new "hide" state is client-only.) Test Plan: Collapsed and expanded inlines, viewed tooltips. Reviewers: chad Reviewed By: chad Maniphest Tasks: T12733 Differential Revision: https://secure.phabricator.com/D18126 --- resources/celerity/map.php | 50 +++++++++---------- .../view/DifferentialChangesetListView.php | 12 ++--- .../view/PHUIDiffInlineCommentDetailView.php | 2 +- .../diff/view/PHUIDiffRevealIconView.php | 2 +- .../rsrc/js/application/diff/DiffChangeset.js | 2 +- .../js/application/diff/DiffChangesetList.js | 46 +++++++---------- .../rsrc/js/application/diff/DiffInline.js | 25 +++++----- 7 files changed, 66 insertions(+), 73 deletions(-) diff --git a/resources/celerity/map.php b/resources/celerity/map.php index e5903df96e..a706777a59 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -13,7 +13,7 @@ return array( 'core.pkg.js' => '1475bd91', 'darkconsole.pkg.js' => '1f9a31bc', 'differential.pkg.css' => '4e99863c', - 'differential.pkg.js' => 'b7504037', + 'differential.pkg.js' => 'ee50e5ae', 'diffusion.pkg.css' => 'b93d9b8c', 'diffusion.pkg.js' => '6134c5a1', 'favicon.ico' => '30672e08', @@ -395,9 +395,9 @@ return array( 'rsrc/js/application/dashboard/behavior-dashboard-move-panels.js' => '408bf173', 'rsrc/js/application/dashboard/behavior-dashboard-query-panel-select.js' => '453c5375', 'rsrc/js/application/dashboard/behavior-dashboard-tab-panel.js' => 'd4eecc63', - 'rsrc/js/application/diff/DiffChangeset.js' => 'd498bddb', - 'rsrc/js/application/diff/DiffChangesetList.js' => '29bbc02c', - 'rsrc/js/application/diff/DiffInline.js' => '20553f71', + 'rsrc/js/application/diff/DiffChangeset.js' => '94f81a34', + 'rsrc/js/application/diff/DiffChangesetList.js' => 'fc6e482d', + 'rsrc/js/application/diff/DiffInline.js' => 'a386f83c', 'rsrc/js/application/diff/behavior-preview-link.js' => '051c7832', 'rsrc/js/application/differential/behavior-comment-preview.js' => '51c5ad07', 'rsrc/js/application/differential/behavior-diff-radios.js' => 'e1ff79b1', @@ -774,9 +774,9 @@ return array( 'phabricator-darklog' => 'c8e1ffe3', 'phabricator-darkmessage' => 'c48cccdd', 'phabricator-dashboard-css' => 'fe5b1869', - 'phabricator-diff-changeset' => 'd498bddb', - 'phabricator-diff-changeset-list' => '29bbc02c', - 'phabricator-diff-inline' => '20553f71', + 'phabricator-diff-changeset' => '94f81a34', + 'phabricator-diff-changeset-list' => 'fc6e482d', + 'phabricator-diff-inline' => 'a386f83c', 'phabricator-drag-and-drop-file-upload' => '58dea2fa', 'phabricator-draggable-list' => 'bea6e7f4', 'phabricator-fatal-config-template-css' => '8f18fa41', @@ -1039,9 +1039,6 @@ return array( 'javelin-install', 'javelin-dom', ), - '20553f71' => array( - 'javelin-dom', - ), '2290aeef' => array( 'javelin-install', 'javelin-dom', @@ -1067,10 +1064,6 @@ return array( 'javelin-install', 'javelin-util', ), - '29bbc02c' => array( - 'javelin-install', - 'phuix-button-view', - ), '2ae077e1' => array( 'javelin-behavior', 'javelin-dom', @@ -1619,6 +1612,17 @@ return array( 'javelin-resource', 'javelin-routable', ), + '94f81a34' => array( + 'javelin-dom', + 'javelin-util', + 'javelin-stratcom', + 'javelin-install', + 'javelin-workflow', + 'javelin-router', + 'javelin-behavior-device', + 'javelin-vector', + 'phabricator-diff-inline', + ), '960f6a39' => array( 'javelin-behavior', 'javelin-dom', @@ -1663,6 +1667,9 @@ return array( 'javelin-install', 'javelin-dom', ), + 'a386f83c' => array( + 'javelin-dom', + ), 'a3a63478' => array( 'phui-workcard-view-css', ), @@ -1986,17 +1993,6 @@ return array( 'javelin-uri', 'javelin-util', ), - 'd498bddb' => array( - 'javelin-dom', - 'javelin-util', - 'javelin-stratcom', - 'javelin-install', - 'javelin-workflow', - 'javelin-router', - 'javelin-behavior-device', - 'javelin-vector', - 'phabricator-diff-inline', - ), 'd4eecc63' => array( 'javelin-behavior', 'javelin-dom', @@ -2158,6 +2154,10 @@ return array( 'javelin-behavior-device', 'phabricator-keyboard-shortcut', ), + 'fc6e482d' => array( + 'javelin-install', + 'phuix-button-view', + ), 'fc91ab6c' => array( 'javelin-behavior', 'javelin-dom', diff --git a/src/applications/differential/view/DifferentialChangesetListView.php b/src/applications/differential/view/DifferentialChangesetListView.php index 25f762ba66..4b9f7c6b5f 100644 --- a/src/applications/differential/view/DifferentialChangesetListView.php +++ b/src/applications/differential/view/DifferentialChangesetListView.php @@ -257,15 +257,15 @@ final class DifferentialChangesetListView extends AphrontView { 'You must select a comment to mark done.' => pht('You must select a comment to mark done.'), - 'Hide or show inline comment.' => - pht('Hide or show inline comment.'), + 'Collapse or expand inline comment.' => + pht('Collapse or expand inline comment.'), 'You must select a comment to hide.' => pht('You must select a comment to hide.'), - 'Jump to next inline comment, including hidden comments.' => - pht('Jump to next inline comment, including hidden comments.'), - 'Jump to previous inline comment, including hidden comments.' => - pht('Jump to previous inline comment, including hidden comments.'), + 'Jump to next inline comment, including collapsed comments.' => + pht('Jump to next inline comment, including collapsed comments.'), + 'Jump to previous inline comment, including collapsed comments.' => + pht('Jump to previous inline comment, including collapsed comments.'), 'This file content has been collapsed.' => pht('This file content has been collapsed.'), diff --git a/src/infrastructure/diff/view/PHUIDiffInlineCommentDetailView.php b/src/infrastructure/diff/view/PHUIDiffInlineCommentDetailView.php index 46853e185c..6d360cd595 100644 --- a/src/infrastructure/diff/view/PHUIDiffInlineCommentDetailView.php +++ b/src/infrastructure/diff/view/PHUIDiffInlineCommentDetailView.php @@ -265,7 +265,7 @@ final class PHUIDiffInlineCommentDetailView if (!$this->preview && $this->canHide()) { $action_buttons[] = id(new PHUIButtonView()) ->setTag('a') - ->setTooltip(pht('Hide Comment')) + ->setTooltip(pht('Collapse')) ->setIcon('fa-times') ->addSigil('hide-inline') ->setMustCapture(true); diff --git a/src/infrastructure/diff/view/PHUIDiffRevealIconView.php b/src/infrastructure/diff/view/PHUIDiffRevealIconView.php index 8ca3eae2c1..dca19725d8 100644 --- a/src/infrastructure/diff/view/PHUIDiffRevealIconView.php +++ b/src/infrastructure/diff/view/PHUIDiffRevealIconView.php @@ -8,7 +8,7 @@ final class PHUIDiffRevealIconView extends AphrontView { ->addSigil('has-tooltip') ->setMetadata( array( - 'tip' => pht('Show Hidden Comment'), + 'tip' => pht('Expand'), 'align' => 'E', 'size' => 275, )); diff --git a/webroot/rsrc/js/application/diff/DiffChangeset.js b/webroot/rsrc/js/application/diff/DiffChangeset.js index c697ba5a6c..739df030af 100644 --- a/webroot/rsrc/js/application/diff/DiffChangeset.js +++ b/webroot/rsrc/js/application/diff/DiffChangeset.js @@ -446,7 +446,7 @@ JX.install('DiffChangeset', { type: block.type, changeset: this, target: inline, - hidden: inline.isHidden(), + collapsed: inline.isCollapsed(), deleted: !inline.getID() && !inline.isEditing(), nodes: { begin: block.items[jj], diff --git a/webroot/rsrc/js/application/diff/DiffChangesetList.js b/webroot/rsrc/js/application/diff/DiffChangesetList.js index b476b8c168..03f3ae9c38 100644 --- a/webroot/rsrc/js/application/diff/DiffChangesetList.js +++ b/webroot/rsrc/js/application/diff/DiffChangesetList.js @@ -19,11 +19,11 @@ JX.install('DiffChangesetList', { var onmenu = JX.bind(this, this._ifawake, this._onmenu); JX.Stratcom.listen('click', 'differential-view-options', onmenu); - var onhide = JX.bind(this, this._ifawake, this._onhide); - JX.Stratcom.listen('click', 'hide-inline', onhide); + var oncollapse = JX.bind(this, this._ifawake, this._oncollapse, true); + JX.Stratcom.listen('click', 'hide-inline', oncollapse); - var onreveal = JX.bind(this, this._ifawake, this._onreveal); - JX.Stratcom.listen('click', 'reveal-inline', onreveal); + var onexpand = JX.bind(this, this._ifawake, this._oncollapse, false); + JX.Stratcom.listen('click', 'reveal-inline', onexpand); var onedit = JX.bind(this, this._ifawake, this._onaction, 'edit'); JX.Stratcom.listen( @@ -158,11 +158,11 @@ JX.install('DiffChangesetList', { label = pht('Jump to previous inline comment.'); this._installJumpKey('p', label, -1, 'comment'); - label = pht('Jump to next inline comment, including hidden comments.'); + label = pht('Jump to next inline comment, including collapsed comments.'); this._installJumpKey('N', label, 1, 'comment', true); label = pht( - 'Jump to previous inline comment, including hidden comments.'); + 'Jump to previous inline comment, including collapsed comments.'); this._installJumpKey('P', label, -1, 'comment', true); label = pht('Hide or show the current file.'); @@ -183,8 +183,8 @@ JX.install('DiffChangesetList', { label = pht('Mark or unmark selected inline comment as done.'); this._installKey('w', label, this._onkeydone); - label = pht('Hide or show inline comment.'); - this._installKey('q', label, this._onkeyhide); + label = pht('Collapse or expand inline comment.'); + this._installKey('q', label, this._onkeycollapse); }, isAsleep: function() { @@ -261,12 +261,12 @@ JX.install('DiffChangesetList', { .register(); }, - _installJumpKey: function(key, label, delta, filter, show_hidden) { + _installJumpKey: function(key, label, delta, filter, show_collapsed) { filter = filter || null; var options = { filter: filter, - hidden: show_hidden + collapsed: show_collapsed }; var handler = JX.bind(this, this._onjumpkey, delta, options); @@ -424,16 +424,16 @@ JX.install('DiffChangesetList', { this._warnUser(pht('You must select a file to hide or show.')); }, - _onkeyhide: function() { + _onkeycollapse: function() { var cursor = this._cursorItem; if (cursor) { if (cursor.type == 'comment') { var inline = cursor.target; - if (inline.canHide()) { + if (inline.canCollapse()) { this.setFocus(null); - inline.setHidden(!inline.isHidden()); + inline.setCollapsed(!inline.isCollapsed()); return; } } @@ -455,7 +455,7 @@ JX.install('DiffChangesetList', { var state = this._getSelectionState(); var filter = options.filter || null; - var hidden = options.hidden || false; + var collapsed = options.collapsed || false; var wrap = options.wrap || false; var attribute = options.attribute || null; @@ -507,10 +507,10 @@ JX.install('DiffChangesetList', { } } - // If the item is hidden, don't select it when iterating with jump + // If the item is collapsed, don't select it when iterating with jump // keys. It can still potentially be selected in other ways. - if (!hidden) { - if (items[cursor].hidden) { + if (!collapsed) { + if (items[cursor].collapsed) { continue; } } @@ -851,20 +851,12 @@ JX.install('DiffChangesetList', { menu.open(); }, - _onhide: function(e) { - this._onhidereveal(e, true); - }, - - _onreveal: function(e) { - this._onhidereveal(e, false); - }, - - _onhidereveal: function(e, is_hide) { + _oncollapse: function(is_collapse, e) { e.kill(); var inline = this._getInlineForEvent(e); - inline.setHidden(is_hide); + inline.setCollapsed(is_collapse); }, _onresize: function() { diff --git a/webroot/rsrc/js/application/diff/DiffInline.js b/webroot/rsrc/js/application/diff/DiffInline.js index baee53a7a4..692d5644a0 100644 --- a/webroot/rsrc/js/application/diff/DiffInline.js +++ b/webroot/rsrc/js/application/diff/DiffInline.js @@ -14,7 +14,6 @@ JX.install('DiffInline', { _phid: null, _changesetID: null, _row: null, - _hidden: false, _number: null, _length: null, _displaySide: null, @@ -30,6 +29,7 @@ JX.install('DiffInline', { _changeset: null, + _isCollapsed: false, _isDraft: null, _isFixed: null, _isEditing: false, @@ -41,7 +41,7 @@ JX.install('DiffInline', { var row_data = JX.Stratcom.getData(row); row_data.inline = this; - this._hidden = row_data.hidden || false; + this._isCollapsed = row_data.hidden || false; // TODO: Get smarter about this once we do more editing, this is pretty // hacky. @@ -225,7 +225,7 @@ JX.install('DiffInline', { return true; }, - canHide: function() { + canCollapse: function() { if (!JX.DOM.scry(this._row, 'a', 'hide-inline').length) { return false; } @@ -254,20 +254,18 @@ JX.install('DiffInline', { this._id = null; this._phid = null; - this._hidden = false; + this._isCollapsed = false; this._originalText = null; return row; }, - setHidden: function(hidden) { - this._hidden = hidden; - - JX.DOM.alterClass(this._row, 'inline-hidden', this._hidden); + setCollapsed: function(collapsed) { + this._isCollapsed = collapsed; var op; - if (hidden) { + if (collapsed) { op = 'hide'; } else { op = 'show'; @@ -280,11 +278,12 @@ JX.install('DiffInline', { .setHandler(JX.bag) .start(); + this._redraw(); this._didUpdate(true); }, - isHidden: function() { - return this._hidden; + isCollapsed: function() { + return this._isCollapsed; }, toggleDone: function() { @@ -703,11 +702,13 @@ JX.install('DiffInline', { _redraw: function() { var is_invisible = (this._isInvisible || this._isDeleted); - var is_loading = (this._isLoading); + var is_loading = this._isLoading; + var is_collapsed = this._isCollapsed; var row = this._row; JX.DOM.alterClass(row, 'differential-inline-hidden', is_invisible); JX.DOM.alterClass(row, 'differential-inline-loading', is_loading); + JX.DOM.alterClass(row, 'inline-hidden', is_collapsed); }, _removeRow: function(row) { From 3be36783b3776ce73f3ec4650f810946895f5a5f Mon Sep 17 00:00:00 2001 From: epriestley Date: Thu, 15 Jun 2017 04:28:21 -0700 Subject: [PATCH 15/34] Consider inline comments with draft checkmarks as "unsubmitted" Summary: Ref T12733. When a revision has unsubmitted checkmarks: - Color the banner yellow. - Show them in the "X unsubmitted" count. - Make the "X unsubmitted" button cycle between all drafts (written but unpublished comments) and "draft done" (checked but unsubmitted "Done" checkbox comments). Test Plan: - Checked a "Done" box, saw "1 unsubmitted" and yellow banner. - Clicked "5 unsubmitted" repeatedly, saw it cycle through all unsubmitted comments and checkboxes. Reviewers: chad Reviewed By: chad Maniphest Tasks: T12733 Differential Revision: https://secure.phabricator.com/D18127 --- resources/celerity/map.php | 62 +++++++++---------- .../view/PHUIDiffInlineCommentDetailView.php | 9 +++ .../differential/changeset-view.css | 3 +- .../rsrc/js/application/diff/DiffChangeset.js | 2 +- .../js/application/diff/DiffChangesetList.js | 29 ++++++--- .../rsrc/js/application/diff/DiffInline.js | 7 +++ 6 files changed, 72 insertions(+), 40 deletions(-) diff --git a/resources/celerity/map.php b/resources/celerity/map.php index a706777a59..03112ea938 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -12,8 +12,8 @@ return array( 'core.pkg.css' => 'ab24402f', 'core.pkg.js' => '1475bd91', 'darkconsole.pkg.js' => '1f9a31bc', - 'differential.pkg.css' => '4e99863c', - 'differential.pkg.js' => 'ee50e5ae', + 'differential.pkg.css' => '4ec4a37a', + 'differential.pkg.js' => '3442216b', 'diffusion.pkg.css' => 'b93d9b8c', 'diffusion.pkg.js' => '6134c5a1', 'favicon.ico' => '30672e08', @@ -64,7 +64,7 @@ return array( 'rsrc/css/application/dashboard/dashboard.css' => 'fe5b1869', 'rsrc/css/application/diff/inline-comment-summary.css' => '51efda3a', 'rsrc/css/application/differential/add-comment.css' => 'c47f8c40', - 'rsrc/css/application/differential/changeset-view.css' => 'c72dba88', + 'rsrc/css/application/differential/changeset-view.css' => 'b5e6be7f', 'rsrc/css/application/differential/core.css' => '5b7b8ff4', 'rsrc/css/application/differential/phui-inline-comment.css' => 'ffd1a542', 'rsrc/css/application/differential/revision-comment.css' => '14b8565a', @@ -395,9 +395,9 @@ return array( 'rsrc/js/application/dashboard/behavior-dashboard-move-panels.js' => '408bf173', 'rsrc/js/application/dashboard/behavior-dashboard-query-panel-select.js' => '453c5375', 'rsrc/js/application/dashboard/behavior-dashboard-tab-panel.js' => 'd4eecc63', - 'rsrc/js/application/diff/DiffChangeset.js' => '94f81a34', - 'rsrc/js/application/diff/DiffChangesetList.js' => 'fc6e482d', - 'rsrc/js/application/diff/DiffInline.js' => 'a386f83c', + 'rsrc/js/application/diff/DiffChangeset.js' => 'cdc5fa19', + 'rsrc/js/application/diff/DiffChangesetList.js' => '4ca11264', + 'rsrc/js/application/diff/DiffInline.js' => '27b6d01f', 'rsrc/js/application/diff/behavior-preview-link.js' => '051c7832', 'rsrc/js/application/differential/behavior-comment-preview.js' => '51c5ad07', 'rsrc/js/application/differential/behavior-diff-radios.js' => 'e1ff79b1', @@ -562,7 +562,7 @@ return array( 'conpherence-thread-manager' => '4d863052', 'conpherence-transaction-css' => '85129c68', 'd3' => 'a11a5ff2', - 'differential-changeset-view-css' => 'c72dba88', + 'differential-changeset-view-css' => 'b5e6be7f', 'differential-core-view-css' => '5b7b8ff4', 'differential-revision-add-comment-css' => 'c47f8c40', 'differential-revision-comment-css' => '14b8565a', @@ -774,9 +774,9 @@ return array( 'phabricator-darklog' => 'c8e1ffe3', 'phabricator-darkmessage' => 'c48cccdd', 'phabricator-dashboard-css' => 'fe5b1869', - 'phabricator-diff-changeset' => '94f81a34', - 'phabricator-diff-changeset-list' => 'fc6e482d', - 'phabricator-diff-inline' => 'a386f83c', + 'phabricator-diff-changeset' => 'cdc5fa19', + 'phabricator-diff-changeset-list' => '4ca11264', + 'phabricator-diff-inline' => '27b6d01f', 'phabricator-drag-and-drop-file-upload' => '58dea2fa', 'phabricator-draggable-list' => 'bea6e7f4', 'phabricator-fatal-config-template-css' => '8f18fa41', @@ -1056,6 +1056,9 @@ return array( 'phabricator-drag-and-drop-file-upload', 'javelin-workboard-board', ), + '27b6d01f' => array( + 'javelin-dom', + ), '2926fff2' => array( 'javelin-behavior', 'javelin-dom', @@ -1231,6 +1234,10 @@ return array( 'javelin-uri', 'phabricator-notification', ), + '4ca11264' => array( + 'javelin-install', + 'phuix-button-view', + ), '4d863052' => array( 'javelin-dom', 'javelin-util', @@ -1612,17 +1619,6 @@ return array( 'javelin-resource', 'javelin-routable', ), - '94f81a34' => array( - 'javelin-dom', - 'javelin-util', - 'javelin-stratcom', - 'javelin-install', - 'javelin-workflow', - 'javelin-router', - 'javelin-behavior-device', - 'javelin-vector', - 'phabricator-diff-inline', - ), '960f6a39' => array( 'javelin-behavior', 'javelin-dom', @@ -1667,9 +1663,6 @@ return array( 'javelin-install', 'javelin-dom', ), - 'a386f83c' => array( - 'javelin-dom', - ), 'a3a63478' => array( 'phui-workcard-view-css', ), @@ -1807,6 +1800,9 @@ return array( 'javelin-dom', 'javelin-util', ), + 'b5e6be7f' => array( + 'phui-inline-comment-view-css', + ), 'b6993408' => array( 'javelin-behavior', 'javelin-stratcom', @@ -1900,9 +1896,6 @@ return array( 'javelin-stratcom', 'javelin-util', ), - 'c72dba88' => array( - 'phui-inline-comment-view-css', - ), 'c7ccd872' => array( 'phui-fontkit-css', ), @@ -1963,6 +1956,17 @@ return array( 'cd2b9b77' => array( 'phui-oi-list-view-css', ), + 'cdc5fa19' => array( + 'javelin-dom', + 'javelin-util', + 'javelin-stratcom', + 'javelin-install', + 'javelin-workflow', + 'javelin-router', + 'javelin-behavior-device', + 'javelin-vector', + 'phabricator-diff-inline', + ), 'd0a99ab4' => array( 'javelin-behavior', 'javelin-typeahead-ondemand-source', @@ -2154,10 +2158,6 @@ return array( 'javelin-behavior-device', 'phabricator-keyboard-shortcut', ), - 'fc6e482d' => array( - 'javelin-install', - 'phuix-button-view', - ), 'fc91ab6c' => array( 'javelin-behavior', 'javelin-dom', diff --git a/src/infrastructure/diff/view/PHUIDiffInlineCommentDetailView.php b/src/infrastructure/diff/view/PHUIDiffInlineCommentDetailView.php index 6d360cd595..27a489a705 100644 --- a/src/infrastructure/diff/view/PHUIDiffInlineCommentDetailView.php +++ b/src/infrastructure/diff/view/PHUIDiffInlineCommentDetailView.php @@ -107,6 +107,14 @@ final class PHUIDiffInlineCommentDetailView break; } + $is_draft_done = false; + switch ($inline->getFixedState()) { + case PhabricatorInlineCommentInterface::STATE_DRAFT: + case PhabricatorInlineCommentInterface::STATE_UNDRAFT: + $is_draft_done = true; + break; + } + $is_synthetic = false; if ($inline->getSyntheticAuthor()) { $is_synthetic = true; @@ -126,6 +134,7 @@ final class PHUIDiffInlineCommentDetailView 'isFixed' => $is_fixed, 'isGhost' => $inline->getIsGhost(), 'isSynthetic' => $is_synthetic, + 'isDraftDone' => $is_draft_done, ); $sigil = 'differential-inline-comment'; diff --git a/webroot/rsrc/css/application/differential/changeset-view.css b/webroot/rsrc/css/application/differential/changeset-view.css index bfde532c44..bf532d0eb3 100644 --- a/webroot/rsrc/css/application/differential/changeset-view.css +++ b/webroot/rsrc/css/application/differential/changeset-view.css @@ -415,7 +415,8 @@ tr.differential-inline-loading { } .diff-banner-has-unsaved, -.diff-banner-has-unsubmitted { +.diff-banner-has-unsubmitted, +.diff-banner-has-draft-done { background: {$sh-yellowbackground}; } diff --git a/webroot/rsrc/js/application/diff/DiffChangeset.js b/webroot/rsrc/js/application/diff/DiffChangeset.js index 739df030af..f73dba0967 100644 --- a/webroot/rsrc/js/application/diff/DiffChangeset.js +++ b/webroot/rsrc/js/application/diff/DiffChangeset.js @@ -454,7 +454,7 @@ JX.install('DiffChangeset', { }, attributes: { unsaved: inline.isEditing(), - unsubmitted: inline.isDraft(), + anyDraft: inline.isDraft() || inline.isDraftDone(), undone: (is_saved && !inline.isDone()), done: (is_saved && inline.isDone()) } diff --git a/webroot/rsrc/js/application/diff/DiffChangesetList.js b/webroot/rsrc/js/application/diff/DiffChangesetList.js index 03f3ae9c38..8200d54a7a 100644 --- a/webroot/rsrc/js/application/diff/DiffChangesetList.js +++ b/webroot/rsrc/js/application/diff/DiffChangesetList.js @@ -1332,6 +1332,7 @@ JX.install('DiffChangesetList', { var changesets = this._changesets; var unsaved = []; var unsubmitted = []; + var draft_done = []; var undone = []; var done = []; @@ -1356,10 +1357,18 @@ JX.install('DiffChangesetList', { continue; } else if (inline.isDraft()) { unsubmitted.push(inline); - } else if (!inline.isDone()) { - undone.push(inline); } else { - done.push(inline); + // NOTE: Unlike other states, an inline may be marked with a + // draft checkmark and still be a "done" or "undone" comment. + if (inline.isDraftDone()) { + draft_done.push(inline); + } + + if (!inline.isDone()) { + undone.push(inline); + } else { + done.push(inline); + } } } } @@ -1374,6 +1383,11 @@ JX.install('DiffChangesetList', { 'diff-banner-has-unsubmitted', !!unsubmitted.length); + JX.DOM.alterClass( + node, + 'diff-banner-has-draft-done', + !!draft_done.length); + var pht = this.getTranslations(); var unsaved_button = this._getUnsavedButton(); var unsubmitted_button = this._getUnsubmittedButton(); @@ -1386,9 +1400,10 @@ JX.install('DiffChangesetList', { JX.DOM.hide(unsaved_button.getNode()); } - if (unsubmitted.length) { - unsubmitted_button.setText( - unsubmitted.length + ' ' + pht('Unsubmitted')); + if (unsubmitted.length || draft_done.length) { + var any_draft_count = unsubmitted.length + draft_done.length; + + unsubmitted_button.setText(any_draft_count + ' ' + pht('Unsubmitted')); JX.DOM.show(unsubmitted_button.getNode()); } else { JX.DOM.hide(unsubmitted_button.getNode()); @@ -1523,7 +1538,7 @@ JX.install('DiffChangesetList', { var options = { filter: 'comment', wrap: true, - attribute: 'unsubmitted' + attribute: 'anyDraft' }; this._onjumpkey(1, options); diff --git a/webroot/rsrc/js/application/diff/DiffInline.js b/webroot/rsrc/js/application/diff/DiffInline.js index 692d5644a0..eb473a3075 100644 --- a/webroot/rsrc/js/application/diff/DiffInline.js +++ b/webroot/rsrc/js/application/diff/DiffInline.js @@ -31,6 +31,7 @@ JX.install('DiffInline', { _isCollapsed: false, _isDraft: null, + _isDraftDone: null, _isFixed: null, _isEditing: false, _isNew: false, @@ -73,6 +74,7 @@ JX.install('DiffInline', { this._isFixed = data.isFixed; this._isGhost = data.isGhost; this._isSynthetic = data.isSynthetic; + this._isDraftDone = data.isDraftDone; this._changesetID = data.changesetID; this._isNew = false; @@ -103,6 +105,10 @@ JX.install('DiffInline', { return this._isSynthetic; }, + isDraftDone: function() { + return this._isDraftDone; + }, + bindToRange: function(data) { this._displaySide = data.displaySide; this._number = parseInt(data.number, 10); @@ -321,6 +327,7 @@ JX.install('DiffInline', { JX.DOM.alterClass(comment, 'inline-state-is-draft', response.draftState); this._isFixed = response.isChecked; + this._isDraftDone = !!response.draftState; this._didUpdate(); }, From b3b30dde6ac99786a77f903823ebf259db6e3adc Mon Sep 17 00:00:00 2001 From: epriestley Date: Thu, 15 Jun 2017 04:51:06 -0700 Subject: [PATCH 16/34] Add options for hidding inlines to the Differential header banner Summary: Fixes T8909. Ref T12733. UI attempts to follow the mock, but is a bit rough since PHUIXButtonView without text in this menu gets weird spacing, we don't have circular buttons yet, and PHUIXActionView without an icon also gets odd spacing. Test Plan: {F5003125} Reviewers: chad Reviewed By: chad Maniphest Tasks: T12733, T8909 Differential Revision: https://secure.phabricator.com/D18128 --- resources/celerity/map.php | 50 +-- .../view/DifferentialChangesetListView.php | 6 + .../rsrc/js/application/diff/DiffChangeset.js | 1 + .../js/application/diff/DiffChangesetList.js | 287 +++++++++++++++--- .../rsrc/js/application/diff/DiffInline.js | 20 +- 5 files changed, 294 insertions(+), 70 deletions(-) diff --git a/resources/celerity/map.php b/resources/celerity/map.php index 03112ea938..a2f711c594 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -13,7 +13,7 @@ return array( 'core.pkg.js' => '1475bd91', 'darkconsole.pkg.js' => '1f9a31bc', 'differential.pkg.css' => '4ec4a37a', - 'differential.pkg.js' => '3442216b', + 'differential.pkg.js' => 'a55a2c13', 'diffusion.pkg.css' => 'b93d9b8c', 'diffusion.pkg.js' => '6134c5a1', 'favicon.ico' => '30672e08', @@ -395,9 +395,9 @@ return array( 'rsrc/js/application/dashboard/behavior-dashboard-move-panels.js' => '408bf173', 'rsrc/js/application/dashboard/behavior-dashboard-query-panel-select.js' => '453c5375', 'rsrc/js/application/dashboard/behavior-dashboard-tab-panel.js' => 'd4eecc63', - 'rsrc/js/application/diff/DiffChangeset.js' => 'cdc5fa19', - 'rsrc/js/application/diff/DiffChangesetList.js' => '4ca11264', - 'rsrc/js/application/diff/DiffInline.js' => '27b6d01f', + 'rsrc/js/application/diff/DiffChangeset.js' => '99abf4cd', + 'rsrc/js/application/diff/DiffChangesetList.js' => 'd442be4a', + 'rsrc/js/application/diff/DiffInline.js' => '1bfa31c7', 'rsrc/js/application/diff/behavior-preview-link.js' => '051c7832', 'rsrc/js/application/differential/behavior-comment-preview.js' => '51c5ad07', 'rsrc/js/application/differential/behavior-diff-radios.js' => 'e1ff79b1', @@ -774,9 +774,9 @@ return array( 'phabricator-darklog' => 'c8e1ffe3', 'phabricator-darkmessage' => 'c48cccdd', 'phabricator-dashboard-css' => 'fe5b1869', - 'phabricator-diff-changeset' => 'cdc5fa19', - 'phabricator-diff-changeset-list' => '4ca11264', - 'phabricator-diff-inline' => '27b6d01f', + 'phabricator-diff-changeset' => '99abf4cd', + 'phabricator-diff-changeset-list' => 'd442be4a', + 'phabricator-diff-inline' => '1bfa31c7', 'phabricator-drag-and-drop-file-upload' => '58dea2fa', 'phabricator-draggable-list' => 'bea6e7f4', 'phabricator-fatal-config-template-css' => '8f18fa41', @@ -1016,6 +1016,9 @@ return array( 'javelin-request', 'javelin-uri', ), + '1bfa31c7' => array( + 'javelin-dom', + ), '1e911d0f' => array( 'javelin-stratcom', 'javelin-request', @@ -1056,9 +1059,6 @@ return array( 'phabricator-drag-and-drop-file-upload', 'javelin-workboard-board', ), - '27b6d01f' => array( - 'javelin-dom', - ), '2926fff2' => array( 'javelin-behavior', 'javelin-dom', @@ -1234,10 +1234,6 @@ return array( 'javelin-uri', 'phabricator-notification', ), - '4ca11264' => array( - 'javelin-install', - 'phuix-button-view', - ), '4d863052' => array( 'javelin-dom', 'javelin-util', @@ -1626,6 +1622,17 @@ return array( 'javelin-mask', 'phabricator-drag-and-drop-file-upload', ), + '99abf4cd' => array( + 'javelin-dom', + 'javelin-util', + 'javelin-stratcom', + 'javelin-install', + 'javelin-workflow', + 'javelin-router', + 'javelin-behavior-device', + 'javelin-vector', + 'phabricator-diff-inline', + ), '9a6dd75c' => array( 'javelin-behavior', 'javelin-stratcom', @@ -1956,17 +1963,6 @@ return array( 'cd2b9b77' => array( 'phui-oi-list-view-css', ), - 'cdc5fa19' => array( - 'javelin-dom', - 'javelin-util', - 'javelin-stratcom', - 'javelin-install', - 'javelin-workflow', - 'javelin-router', - 'javelin-behavior-device', - 'javelin-vector', - 'phabricator-diff-inline', - ), 'd0a99ab4' => array( 'javelin-behavior', 'javelin-typeahead-ondemand-source', @@ -1991,6 +1987,10 @@ return array( 'd254d646' => array( 'javelin-util', ), + 'd442be4a' => array( + 'javelin-install', + 'phuix-button-view', + ), 'd4505101' => array( 'javelin-stratcom', 'javelin-install', diff --git a/src/applications/differential/view/DifferentialChangesetListView.php b/src/applications/differential/view/DifferentialChangesetListView.php index 4b9f7c6b5f..6aa9020a95 100644 --- a/src/applications/differential/view/DifferentialChangesetListView.php +++ b/src/applications/differential/view/DifferentialChangesetListView.php @@ -279,6 +279,12 @@ final class DifferentialChangesetListView extends AphrontView { 'Unsaved' => pht('Unsaved'), 'Unsubmitted' => pht('Unsubmitted'), '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'), ), )); diff --git a/webroot/rsrc/js/application/diff/DiffChangeset.js b/webroot/rsrc/js/application/diff/DiffChangeset.js index f73dba0967..72eeae294a 100644 --- a/webroot/rsrc/js/application/diff/DiffChangeset.js +++ b/webroot/rsrc/js/application/diff/DiffChangeset.js @@ -446,6 +446,7 @@ JX.install('DiffChangeset', { type: block.type, changeset: this, target: inline, + hidden: inline.isHidden(), collapsed: inline.isCollapsed(), deleted: !inline.getID() && !inline.isEditing(), nodes: { diff --git a/webroot/rsrc/js/application/diff/DiffChangesetList.js b/webroot/rsrc/js/application/diff/DiffChangesetList.js index 8200d54a7a..25f5d57698 100644 --- a/webroot/rsrc/js/application/diff/DiffChangesetList.js +++ b/webroot/rsrc/js/application/diff/DiffChangesetList.js @@ -117,6 +117,10 @@ JX.install('DiffChangesetList', { _doneButton: null, _doneMode: null, + _dropdownMenu: null, + _menuButton: null, + _menuItems: null, + sleep: function() { this._asleep = true; @@ -458,6 +462,7 @@ JX.install('DiffChangesetList', { var collapsed = options.collapsed || false; var wrap = options.wrap || false; var attribute = options.attribute || null; + var show = options.show || false; var cursor = state.cursor; var items = state.items; @@ -529,6 +534,15 @@ JX.install('DiffChangesetList', { } } + // If this item is a hidden inline but we're clicking a button which + // selects inlines of a particular type, make it visible again. + if (items[cursor].hidden) { + if (!show) { + continue; + } + items[cursor].target.setHidden(false); + } + // Otherwise, we've found a valid item to select. break; } @@ -1314,6 +1328,13 @@ JX.install('DiffChangesetList', { }, _redrawBanner: function() { + // If the inline comment menu is open and we've done a redraw, close it. + // In particular, this makes it close when you scroll the document: + // otherwise, it stays open but the banner moves underneath it. + if (this._dropdownMenu) { + this._dropdownMenu.close(); + } + var node = this._getBannerNode(); var changeset = this._getVisibleChangeset(); @@ -1329,49 +1350,13 @@ JX.install('DiffChangesetList', { return; } - var changesets = this._changesets; - var unsaved = []; - var unsubmitted = []; - var draft_done = []; - var undone = []; - var done = []; + var inlines = this._getInlinesByType(); - for (var ii = 0; ii < changesets.length; ii++) { - var inlines = changesets[ii].getInlines(); - for (var jj = 0; jj < inlines.length; jj++) { - var inline = inlines[jj]; - - if (inline.isDeleted()) { - continue; - } - - if (inline.isSynthetic()) { - continue; - } - - if (inline.isEditing()) { - unsaved.push(inline); - } else if (!inline.getID()) { - // These are new comments which have been cancelled, and do not - // count as anything. - continue; - } else if (inline.isDraft()) { - unsubmitted.push(inline); - } else { - // NOTE: Unlike other states, an inline may be marked with a - // draft checkmark and still be a "done" or "undone" comment. - if (inline.isDraftDone()) { - draft_done.push(inline); - } - - if (!inline.isDone()) { - undone.push(inline); - } else { - done.push(inline); - } - } - } - } + var unsaved = inlines.unsaved; + var unsubmitted = inlines.unsubmitted; + var undone = inlines.undone; + var done = inlines.done; + var draft_done = inlines.draftDone; JX.DOM.alterClass( node, @@ -1392,6 +1377,7 @@ JX.install('DiffChangesetList', { var unsaved_button = this._getUnsavedButton(); var unsubmitted_button = this._getUnsubmittedButton(); var done_button = this._getDoneButton(); + var menu_button = this._getMenuButton(); if (unsaved.length) { unsaved_button.setText(unsaved.length + ' ' + pht('Unsaved')); @@ -1457,7 +1443,8 @@ JX.install('DiffChangesetList', { var buttons_list = [ unsaved_button.getNode(), unsubmitted_button.getNode(), - done_button.getNode() + done_button.getNode(), + menu_button.getNode() ]; var buttons_view = JX.$N('div', buttons_attrs, buttons_list); @@ -1470,6 +1457,104 @@ JX.install('DiffChangesetList', { document.body.appendChild(node); }, + _getInlinesByType: function() { + var changesets = this._changesets; + var unsaved = []; + var unsubmitted = []; + var undone = []; + var done = []; + var draft_done = []; + + var visible_done = []; + var visible_collapsed = []; + var visible_ghosts = []; + var visible = []; + var hidden = []; + + for (var ii = 0; ii < changesets.length; ii++) { + var inlines = changesets[ii].getInlines(); + var inline; + var jj; + for (jj = 0; jj < inlines.length; jj++) { + inline = inlines[jj]; + + if (inline.isDeleted()) { + continue; + } + + if (inline.isSynthetic()) { + continue; + } + + if (inline.isEditing()) { + unsaved.push(inline); + } else if (!inline.getID()) { + // These are new comments which have been cancelled, and do not + // count as anything. + continue; + } else if (inline.isDraft()) { + unsubmitted.push(inline); + } else { + // NOTE: Unlike other states, an inline may be marked with a + // draft checkmark and still be a "done" or "undone" comment. + if (inline.isDraftDone()) { + draft_done.push(inline); + } + + if (!inline.isDone()) { + undone.push(inline); + } else { + done.push(inline); + } + } + } + + for (jj = 0; jj < inlines.length; jj++) { + inline = inlines[jj]; + if (inline.isDeleted()) { + continue; + } + + if (inline.isEditing()) { + continue; + } + + if (inline.isHidden()) { + hidden.push(inline); + continue; + } + + visible.push(inline); + + if (inline.isDone()) { + visible_done.push(inline); + } + + if (inline.isCollapsed()) { + visible_collapsed.push(inline); + } + + if (inline.isGhost()) { + visible_ghosts.push(inline); + } + } + } + + return { + unsaved: unsaved, + unsubmitted: unsubmitted, + undone: undone, + done: done, + draftDone: draft_done, + visibleDone: visible_done, + visibleGhosts: visible_ghosts, + visibleCollapsed: visible_collapsed, + visible: visible, + hidden: hidden + }; + + }, + _getUnsavedButton: function() { if (!this._unsavedButton) { var button = new JX.PHUIXButtonView() @@ -1520,12 +1605,126 @@ JX.install('DiffChangesetList', { return this._doneButton; }, + + _getMenuButton: function() { + if (!this._menuButton) { + var button = new JX.PHUIXButtonView() + .setIcon('fa-gear') + .setButtonType(JX.PHUIXButtonView.BUTTONTYPE_SIMPLE); + + var dropdown = new JX.PHUIXDropdownMenu(button.getNode()); + this._menuItems = {}; + + var list = new JX.PHUIXActionListView(); + dropdown.setContent(list.getNode()); + + var map = { + hideDone: { + type: 'done' + }, + hideCollapsed: { + type: 'collapsed' + }, + hideGhosts: { + type: 'ghosts' + }, + hideAll: { + type: 'all' + }, + showAll: { + type: 'show' + } + }; + + for (var k in map) { + var spec = map[k]; + + var handler = JX.bind(this, this._onhideinlines, spec.type); + var item = new JX.PHUIXActionView() + .setHandler(handler); + + list.addItem(item); + this._menuItems[k] = item; + } + + dropdown.listen('open', JX.bind(this, this._ondropdown)); + + this._menuButton = button; + this._dropdownMenu = dropdown; + } + + return this._menuButton; + }, + + _ondropdown: function() { + var inlines = this._getInlinesByType(); + var items = this._menuItems; + var pht = this.getTranslations(); + + items.hideDone + .setName(pht('Hide "Done" Inlines')) + .setDisabled(!inlines.visibleDone.length); + + items.hideCollapsed + .setName(pht('Hide Collapsed Inlines')) + .setDisabled(!inlines.visibleCollapsed.length); + + items.hideGhosts + .setName(pht('Hide Older Inlines')) + .setDisabled(!inlines.visibleGhosts.length); + + items.hideAll + .setName(pht('Hide All Inlines')) + .setDisabled(!inlines.visible.length); + + items.showAll + .setName(pht('Show All Inlines')) + .setDisabled(!inlines.hidden.length); + }, + + _onhideinlines: function(type, e) { + this._dropdownMenu.close(); + e.prevent(); + + var inlines = this._getInlinesByType(); + + // Clear the selection state since we end up in a weird place if the + // user hides the selected inline. + this._setSelectionState(null); + + var targets; + var mode = true; + switch (type) { + case 'done': + targets = inlines.visibleDone; + break; + case 'collapsed': + targets = inlines.visibleCollapsed; + break; + case 'ghosts': + targets = inlines.visibleGhosts; + break; + case 'all': + targets = inlines.visible; + break; + case 'show': + targets = inlines.hidden; + mode = false; + break; + } + + for (var ii = 0; ii < targets.length; ii++) { + targets[ii].setHidden(mode); + } + }, + _onunsavedclick: function(e) { e.kill(); var options = { filter: 'comment', wrap: true, + show: true, attribute: 'unsaved' }; @@ -1538,6 +1737,7 @@ JX.install('DiffChangesetList', { var options = { filter: 'comment', wrap: true, + show: true, attribute: 'anyDraft' }; @@ -1550,6 +1750,7 @@ JX.install('DiffChangesetList', { var options = { filter: 'comment', wrap: true, + show: true, attribute: this._doneMode }; diff --git a/webroot/rsrc/js/application/diff/DiffInline.js b/webroot/rsrc/js/application/diff/DiffInline.js index eb473a3075..1c93959b32 100644 --- a/webroot/rsrc/js/application/diff/DiffInline.js +++ b/webroot/rsrc/js/application/diff/DiffInline.js @@ -36,6 +36,7 @@ JX.install('DiffInline', { _isEditing: false, _isNew: false, _isSynthetic: false, + _isHidden: false, bindToRow: function(row) { this._row = row; @@ -109,6 +110,14 @@ JX.install('DiffInline', { return this._isDraftDone; }, + isHidden: function() { + return this._isHidden; + }, + + isGhost: function() { + return this._isGhost; + }, + bindToRange: function(data) { this._displaySide = data.displaySide; this._number = parseInt(data.number, 10); @@ -207,6 +216,12 @@ JX.install('DiffInline', { return this; }, + setHidden: function(hidden) { + this._isHidden = hidden; + this._redraw(); + return this; + }, + canReply: function() { if (!this._hasAction('reply')) { return false; @@ -708,9 +723,10 @@ JX.install('DiffInline', { }, _redraw: function() { - var is_invisible = (this._isInvisible || this._isDeleted); + var is_invisible = + (this._isInvisible || this._isDeleted || this._isHidden); var is_loading = this._isLoading; - var is_collapsed = this._isCollapsed; + var is_collapsed = (this._isCollapsed && !this._isHidden); var row = this._row; JX.DOM.alterClass(row, 'differential-inline-hidden', is_invisible); From 9b93697d52f40753799683ce461fcc02f45d7ef5 Mon Sep 17 00:00:00 2001 From: epriestley Date: Thu, 15 Jun 2017 05:31:42 -0700 Subject: [PATCH 17/34] Move "List Inline Comments" to the inline header dropdown menu Summary: See D18128. Ref T12733. Ref T8250. Test Plan: {F5003153} Reviewers: chad Reviewed By: chad Maniphest Tasks: T12733, T8250 Differential Revision: https://secure.phabricator.com/D18129 --- resources/celerity/map.php | 50 +++++++++---------- .../DifferentialRevisionViewController.php | 12 ++--- .../view/DifferentialChangesetListView.php | 13 +++++ .../js/application/diff/DiffChangesetList.js | 17 ++++++- .../differential/behavior-populate.js | 3 +- webroot/rsrc/js/phuix/PHUIXActionView.js | 10 ++++ 6 files changed, 72 insertions(+), 33 deletions(-) diff --git a/resources/celerity/map.php b/resources/celerity/map.php index a2f711c594..98d677d53c 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -10,10 +10,10 @@ return array( 'conpherence.pkg.css' => 'ff161f2d', 'conpherence.pkg.js' => 'b5b51108', 'core.pkg.css' => 'ab24402f', - 'core.pkg.js' => '1475bd91', + 'core.pkg.js' => '5d80e0db', 'darkconsole.pkg.js' => '1f9a31bc', 'differential.pkg.css' => '4ec4a37a', - 'differential.pkg.js' => 'a55a2c13', + 'differential.pkg.js' => 'd4ab0e81', 'diffusion.pkg.css' => 'b93d9b8c', 'diffusion.pkg.js' => '6134c5a1', 'favicon.ico' => '30672e08', @@ -396,12 +396,12 @@ return array( 'rsrc/js/application/dashboard/behavior-dashboard-query-panel-select.js' => '453c5375', 'rsrc/js/application/dashboard/behavior-dashboard-tab-panel.js' => 'd4eecc63', 'rsrc/js/application/diff/DiffChangeset.js' => '99abf4cd', - 'rsrc/js/application/diff/DiffChangesetList.js' => 'd442be4a', + 'rsrc/js/application/diff/DiffChangesetList.js' => '79de07c6', 'rsrc/js/application/diff/DiffInline.js' => '1bfa31c7', 'rsrc/js/application/diff/behavior-preview-link.js' => '051c7832', 'rsrc/js/application/differential/behavior-comment-preview.js' => '51c5ad07', 'rsrc/js/application/differential/behavior-diff-radios.js' => 'e1ff79b1', - 'rsrc/js/application/differential/behavior-populate.js' => '5e41c819', + 'rsrc/js/application/differential/behavior-populate.js' => '419998ab', 'rsrc/js/application/differential/behavior-user-select.js' => 'a8d8459d', 'rsrc/js/application/diffusion/DiffusionLocateFileSource.js' => 'c93358e3', 'rsrc/js/application/diffusion/behavior-audit-preview.js' => 'd835b03a', @@ -526,7 +526,7 @@ return array( 'rsrc/js/phui/behavior-phui-submenu.js' => 'a6f7a73b', 'rsrc/js/phui/behavior-phui-tab-group.js' => '0a0b10e9', 'rsrc/js/phuix/PHUIXActionListView.js' => 'b5c256b8', - 'rsrc/js/phuix/PHUIXActionView.js' => 'b3465b9b', + 'rsrc/js/phuix/PHUIXActionView.js' => '442efd08', 'rsrc/js/phuix/PHUIXAutocomplete.js' => 'f6699267', 'rsrc/js/phuix/PHUIXButtonView.js' => 'a37126bd', 'rsrc/js/phuix/PHUIXDropdownMenu.js' => '8018ee50', @@ -616,7 +616,7 @@ return array( 'javelin-behavior-diff-preview-link' => '051c7832', 'javelin-behavior-differential-diff-radios' => 'e1ff79b1', 'javelin-behavior-differential-feedback-preview' => '51c5ad07', - 'javelin-behavior-differential-populate' => '5e41c819', + 'javelin-behavior-differential-populate' => '419998ab', 'javelin-behavior-differential-user-select' => 'a8d8459d', 'javelin-behavior-diffusion-browse-file' => '054a0f0b', 'javelin-behavior-diffusion-commit-branches' => 'bdaf4d04', @@ -775,7 +775,7 @@ return array( 'phabricator-darkmessage' => 'c48cccdd', 'phabricator-dashboard-css' => 'fe5b1869', 'phabricator-diff-changeset' => '99abf4cd', - 'phabricator-diff-changeset-list' => 'd442be4a', + 'phabricator-diff-changeset-list' => '79de07c6', 'phabricator-diff-inline' => '1bfa31c7', 'phabricator-drag-and-drop-file-upload' => '58dea2fa', 'phabricator-draggable-list' => 'bea6e7f4', @@ -878,7 +878,7 @@ return array( 'phui-workcard-view-css' => 'cca5fa92', 'phui-workpanel-view-css' => 'a3a63478', 'phuix-action-list-view' => 'b5c256b8', - 'phuix-action-view' => 'b3465b9b', + 'phuix-action-view' => '442efd08', 'phuix-autocomplete' => 'f6699267', 'phuix-button-view' => 'a37126bd', 'phuix-dropdown-menu' => '8018ee50', @@ -1160,6 +1160,14 @@ return array( 'javelin-workflow', 'phabricator-draggable-list', ), + '419998ab' => array( + 'javelin-behavior', + 'javelin-dom', + 'javelin-stratcom', + 'phabricator-tooltip', + 'phabricator-diff-changeset-list', + 'phabricator-diff-changeset', + ), 42126667 => array( 'javelin-behavior', 'javelin-dom', @@ -1174,6 +1182,11 @@ return array( 'javelin-workflow', 'javelin-workboard-controller', ), + '442efd08' => array( + 'javelin-install', + 'javelin-dom', + 'javelin-util', + ), '44959b73' => array( 'javelin-util', 'javelin-uri', @@ -1335,14 +1348,6 @@ return array( 'phabricator-phtize', 'javelin-dom', ), - '5e41c819' => array( - 'javelin-behavior', - 'javelin-dom', - 'javelin-stratcom', - 'phabricator-tooltip', - 'phabricator-diff-changeset-list', - 'phabricator-diff-changeset', - ), '5e9f347c' => array( 'javelin-behavior', 'multirow-row-manager', @@ -1471,6 +1476,10 @@ return array( 'javelin-behavior', 'javelin-quicksand', ), + '79de07c6' => array( + 'javelin-install', + 'phuix-button-view', + ), '7a68dda3' => array( 'owners-path-editor', 'javelin-behavior', @@ -1778,11 +1787,6 @@ return array( 'javelin-uri', 'javelin-request', ), - 'b3465b9b' => array( - 'javelin-install', - 'javelin-dom', - 'javelin-util', - ), 'b3a4b884' => array( 'javelin-behavior', 'phabricator-prefab', @@ -1987,10 +1991,6 @@ return array( 'd254d646' => array( 'javelin-util', ), - 'd442be4a' => array( - 'javelin-install', - 'phuix-button-view', - ), 'd4505101' => array( 'javelin-stratcom', 'javelin-install', diff --git a/src/applications/differential/controller/DifferentialRevisionViewController.php b/src/applications/differential/controller/DifferentialRevisionViewController.php index 0f3675f8f6..f19ff37360 100644 --- a/src/applications/differential/controller/DifferentialRevisionViewController.php +++ b/src/applications/differential/controller/DifferentialRevisionViewController.php @@ -281,6 +281,12 @@ final class DifferentialRevisionViewController extends DifferentialController { ->setTitle(pht('Diff %s', $target->getID())) ->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) { $changeset_view->setRepository($repository); } @@ -574,12 +580,6 @@ final class DifferentialRevisionViewController extends DifferentialController { ->setDisabled(!$can_edit) ->setWorkflow(!$can_edit)); - $curtain->addAction( - id(new PhabricatorActionView()) - ->setIcon('fa-indent') - ->setHref("/differential/revision/inlines/{$revision_id}/") - ->setName(pht('List Inline Comments'))); - $curtain->addAction( id(new PhabricatorActionView()) ->setIcon('fa-upload') diff --git a/src/applications/differential/view/DifferentialChangesetListView.php b/src/applications/differential/view/DifferentialChangesetListView.php index 6aa9020a95..2787356bd2 100644 --- a/src/applications/differential/view/DifferentialChangesetListView.php +++ b/src/applications/differential/view/DifferentialChangesetListView.php @@ -14,6 +14,7 @@ final class DifferentialChangesetListView extends AphrontView { private $standaloneURI; private $leftRawFileURI; private $rightRawFileURI; + private $inlineListURI; private $symbolIndexes = array(); private $repository; @@ -64,6 +65,15 @@ final class DifferentialChangesetListView extends AphrontView { return $this; } + public function setInlineListURI($uri) { + $this->inlineListURI = $uri; + return $this; + } + + public function getInlineListURI() { + return $this->inlineListURI; + } + public function setRepository(PhabricatorRepository $repository) { $this->repository = $repository; return $this; @@ -208,6 +218,7 @@ final class DifferentialChangesetListView extends AphrontView { array( 'changesetViewIDs' => $ids, 'inlineURI' => $this->inlineURI, + 'inlineListURI' => $this->inlineListURI, 'pht' => array( 'Open in Editor' => pht('Open in Editor'), 'Show All Context' => pht('Show All Context'), @@ -285,6 +296,8 @@ final class DifferentialChangesetListView extends AphrontView { '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'), ), )); diff --git a/webroot/rsrc/js/application/diff/DiffChangesetList.js b/webroot/rsrc/js/application/diff/DiffChangesetList.js index 25f5d57698..808527876c 100644 --- a/webroot/rsrc/js/application/diff/DiffChangesetList.js +++ b/webroot/rsrc/js/application/diff/DiffChangesetList.js @@ -88,7 +88,8 @@ JX.install('DiffChangesetList', { properties: { translations: null, - inlineURI: null + inlineURI: null, + inlineListURI: null }, members: { @@ -1649,6 +1650,20 @@ JX.install('DiffChangesetList', { dropdown.listen('open', JX.bind(this, this._ondropdown)); + var pht = this.getTranslations(); + + if (this.getInlineListURI()) { + list.addItem( + new JX.PHUIXActionView() + .setDivider(true)); + + list.addItem( + new JX.PHUIXActionView() + .setIcon('fa-link') + .setName(pht('List Inline Comments')) + .setHref(this.getInlineListURI())); + } + this._menuButton = button; this._dropdownMenu = dropdown; } diff --git a/webroot/rsrc/js/application/differential/behavior-populate.js b/webroot/rsrc/js/application/differential/behavior-populate.js index e5b0d5039d..0a4a7912e4 100644 --- a/webroot/rsrc/js/application/differential/behavior-populate.js +++ b/webroot/rsrc/js/application/differential/behavior-populate.js @@ -60,7 +60,8 @@ JX.behavior('differential-populate', function(config, statics) { var changeset_list = new JX.DiffChangesetList() .setTranslations(JX.phtize(config.pht)) - .setInlineURI(config.inlineURI); + .setInlineURI(config.inlineURI) + .setInlineListURI(config.inlineListURI); // Install and activate the current page. var page_id = JX.Quicksand.getCurrentPageID(); diff --git a/webroot/rsrc/js/phuix/PHUIXActionView.js b/webroot/rsrc/js/phuix/PHUIXActionView.js index d5d849e733..2db58dbdc4 100644 --- a/webroot/rsrc/js/phuix/PHUIXActionView.js +++ b/webroot/rsrc/js/phuix/PHUIXActionView.js @@ -16,6 +16,7 @@ JX.install('PHUIXActionView', { _label: false, _handler: null, _selected: false, + _divider: false, _iconNode: null, _nameNode: null, @@ -41,6 +42,15 @@ JX.install('PHUIXActionView', { return this; }, + setDivider: function(divider) { + this._divider = divider; + JX.DOM.alterClass( + this.getNode(), + 'phabricator-action-view-type-divider', + divider); + return this; + }, + setSelected: function(selected) { this._selected = selected; JX.DOM.alterClass( From 9540ed7ec2ee180dc6edd9bada92c0b18b9ead7b Mon Sep 17 00:00:00 2001 From: Chad Little Date: Sun, 18 Jun 2017 08:50:50 +0200 Subject: [PATCH 18/34] Use visibility hidden on remarkup checkboxes Summary: Fixes T12850, marks it hidden with zero width so the element still exists in the DOM Test Plan: T12850 code, locally Reviewers: epriestley, amckinley, avivey Reviewed By: avivey Subscribers: Korvin Maniphest Tasks: T12850 Differential Revision: https://secure.phabricator.com/D18130 --- resources/celerity/map.php | 6 +++--- webroot/rsrc/css/core/remarkup.css | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/resources/celerity/map.php b/resources/celerity/map.php index 98d677d53c..3e80c99baa 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -9,7 +9,7 @@ return array( 'names' => array( 'conpherence.pkg.css' => 'ff161f2d', 'conpherence.pkg.js' => 'b5b51108', - 'core.pkg.css' => 'ab24402f', + 'core.pkg.css' => '6d40b714', 'core.pkg.js' => '5d80e0db', 'darkconsole.pkg.js' => '1f9a31bc', 'differential.pkg.css' => '4ec4a37a', @@ -115,7 +115,7 @@ return array( 'rsrc/css/application/tokens/tokens.css' => '3d0f239e', 'rsrc/css/application/uiexample/example.css' => '528b19de', 'rsrc/css/core/core.css' => '23beb330', - 'rsrc/css/core/remarkup.css' => '509fb36e', + 'rsrc/css/core/remarkup.css' => 'eb37bd0d', 'rsrc/css/core/syntax.css' => 'cae95e89', 'rsrc/css/core/z-index.css' => '9d8f7c4b', 'rsrc/css/diviner/diviner-shared.css' => '896f1d43', @@ -795,7 +795,7 @@ return array( 'phabricator-object-selector-css' => '85ee8ce6', 'phabricator-phtize' => 'd254d646', 'phabricator-prefab' => 'c5af80a2', - 'phabricator-remarkup-css' => '509fb36e', + 'phabricator-remarkup-css' => 'eb37bd0d', 'phabricator-search-results-css' => '8f8e08ed', 'phabricator-shaped-request' => '7cbe244b', 'phabricator-slowvote-css' => 'a94b7230', diff --git a/webroot/rsrc/css/core/remarkup.css b/webroot/rsrc/css/core/remarkup.css index 98529b9434..1de7ccf85a 100644 --- a/webroot/rsrc/css/core/remarkup.css +++ b/webroot/rsrc/css/core/remarkup.css @@ -128,7 +128,8 @@ } .phabricator-remarkup .remarkup-list-with-checkmarks input { - display: none; + visibility: hidden; + width: 0; } .phabricator-remarkup .remarkup-list-with-checkmarks From d0898116d8c265065481b970f4ea1fa58547562d Mon Sep 17 00:00:00 2001 From: Chad Little Date: Sun, 18 Jun 2017 09:53:43 +0200 Subject: [PATCH 19/34] Add a graph view page to Diffusion Summary: Fixes T12840. This adds a parallel "graph" button next to history on home and on the history list page. I'll think more about better placement of how to get to this page with the upcoming redesign that's still sitting in Pholio. Test Plan: View History, View Graph, Try pager, go to a file, click view history, see no graph button. Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Maniphest Tasks: T12840 Differential Revision: https://secure.phabricator.com/D18131 --- src/__phutil_library_map__.php | 2 + .../PhabricatorDiffusionApplication.php | 1 + .../controller/DiffusionController.php | 3 + .../controller/DiffusionGraphController.php | 108 ++++++++++++++++++ .../controller/DiffusionHistoryController.php | 28 +++-- .../DiffusionRepositoryController.php | 54 +++++---- .../storage/PhabricatorRepository.php | 2 + 7 files changed, 161 insertions(+), 37 deletions(-) create mode 100644 src/applications/diffusion/controller/DiffusionGraphController.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index bca514a06e..f1fd9648cd 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -729,6 +729,7 @@ phutil_register_library_map(array( 'DiffusionGitResponse' => 'applications/diffusion/response/DiffusionGitResponse.php', 'DiffusionGitSSHWorkflow' => 'applications/diffusion/ssh/DiffusionGitSSHWorkflow.php', 'DiffusionGitUploadPackSSHWorkflow' => 'applications/diffusion/ssh/DiffusionGitUploadPackSSHWorkflow.php', + 'DiffusionGraphController' => 'applications/diffusion/controller/DiffusionGraphController.php', 'DiffusionHistoryController' => 'applications/diffusion/controller/DiffusionHistoryController.php', 'DiffusionHistoryListView' => 'applications/diffusion/view/DiffusionHistoryListView.php', 'DiffusionHistoryQueryConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionHistoryQueryConduitAPIMethod.php', @@ -5706,6 +5707,7 @@ phutil_register_library_map(array( 'DiffusionRepositoryClusterEngineLogInterface', ), 'DiffusionGitUploadPackSSHWorkflow' => 'DiffusionGitSSHWorkflow', + 'DiffusionGraphController' => 'DiffusionController', 'DiffusionHistoryController' => 'DiffusionController', 'DiffusionHistoryListView' => 'DiffusionHistoryView', 'DiffusionHistoryQueryConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod', diff --git a/src/applications/diffusion/application/PhabricatorDiffusionApplication.php b/src/applications/diffusion/application/PhabricatorDiffusionApplication.php index c07c89159b..dc1b120138 100644 --- a/src/applications/diffusion/application/PhabricatorDiffusionApplication.php +++ b/src/applications/diffusion/application/PhabricatorDiffusionApplication.php @@ -56,6 +56,7 @@ final class PhabricatorDiffusionApplication extends PhabricatorApplication { 'repository/(?P.*)' => 'DiffusionRepositoryController', 'change/(?P.*)' => 'DiffusionChangeController', 'history/(?P.*)' => 'DiffusionHistoryController', + 'graph/(?P.*)' => 'DiffusionGraphController', 'browse/(?P.*)' => 'DiffusionBrowseController', 'lastmodified/(?P.*)' => 'DiffusionLastModifiedController', 'diff/' => 'DiffusionDiffController', diff --git a/src/applications/diffusion/controller/DiffusionController.php b/src/applications/diffusion/controller/DiffusionController.php index 52465da410..abebbace90 100644 --- a/src/applications/diffusion/controller/DiffusionController.php +++ b/src/applications/diffusion/controller/DiffusionController.php @@ -204,6 +204,9 @@ abstract class DiffusionController extends PhabricatorController { case 'history': $view_name = pht('History'); break; + case 'graph': + $view_name = pht('Graph'); + break; case 'browse': $view_name = pht('Browse'); break; diff --git a/src/applications/diffusion/controller/DiffusionGraphController.php b/src/applications/diffusion/controller/DiffusionGraphController.php new file mode 100644 index 0000000000..8428a8152d --- /dev/null +++ b/src/applications/diffusion/controller/DiffusionGraphController.php @@ -0,0 +1,108 @@ +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; + + } + +} diff --git a/src/applications/diffusion/controller/DiffusionHistoryController.php b/src/applications/diffusion/controller/DiffusionHistoryController.php index b8a1877ddf..c2f718f11e 100644 --- a/src/applications/diffusion/controller/DiffusionHistoryController.php +++ b/src/applications/diffusion/controller/DiffusionHistoryController.php @@ -77,24 +77,28 @@ final class DiffusionHistoryController extends DiffusionController { $viewer = $this->getViewer(); $tag = $this->renderCommitHashTag($drequest); - $browse_uri = $drequest->generateURI( - array( - 'action' => 'browse', - )); - - $browse_button = id(new PHUIButtonView()) - ->setTag('a') - ->setText(pht('Browse')) - ->setHref($browse_uri) - ->setIcon('fa-code'); + $show_graph = !strlen($drequest->getPath()); $header = id(new PHUIHeaderView()) ->setUser($viewer) ->setPolicyObject($drequest->getRepository()) ->addTag($tag) ->setHeader($this->renderPathLinks($drequest, $mode = 'history')) - ->setHeaderIcon('fa-clock-o') - ->addActionLink($browse_button); + ->setHeaderIcon('fa-clock-o'); + + 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; diff --git a/src/applications/diffusion/controller/DiffusionRepositoryController.php b/src/applications/diffusion/controller/DiffusionRepositoryController.php index e341b87972..362f78bd3f 100644 --- a/src/applications/diffusion/controller/DiffusionRepositoryController.php +++ b/src/applications/diffusion/controller/DiffusionRepositoryController.php @@ -451,11 +451,11 @@ final class DiffusionRepositoryController extends DiffusionController { $header->setSubheader(pht('Showing %d branches.', $limit)); } - $button = new PHUIButtonView(); - $button->setText(pht('Show All')); - $button->setTag('a'); - $button->setIcon('fa-code-fork'); - $button->setHref($drequest->generateURI( + $button = id(new PHUIButtonView()) + ->setText(pht('Show All')) + ->setTag('a') + ->setIcon('fa-code-fork') + ->setHref($drequest->generateURI( array( 'action' => 'branches', ))); @@ -511,11 +511,11 @@ final class DiffusionRepositoryController extends DiffusionController { pht('Showing the %d most recent tags.', $tag_limit)); } - $button = new PHUIButtonView(); - $button->setText(pht('Show All Tags')); - $button->setTag('a'); - $button->setIcon('fa-tag'); - $button->setHref($drequest->generateURI( + $button = id(new PHUIButtonView()) + ->setText(pht('Show All Tags')) + ->setTag('a') + ->setIcon('fa-tag') + ->setHref($drequest->generateURI( array( 'action' => 'tags', ))); @@ -567,23 +567,30 @@ final class DiffusionRepositoryController extends DiffusionController { $history_table->setIsHead(true); - $icon = id(new PHUIIconView()) - ->setIcon('fa-list-alt'); - - $button = id(new PHUIButtonView()) - ->setText(pht('View History')) + $history = id(new PHUIButtonView()) + ->setText(pht('History')) ->setHref($drequest->generateURI( array( 'action' => 'history', ))) ->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()) ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY); $header = id(new PHUIHeaderView()) ->setHeader(pht('Recent Commits')) - ->addActionLink($button); + ->addActionLink($graph) + ->addActionLink($history); $panel->setHeader($header); $panel->setTable($history_table); @@ -672,14 +679,11 @@ final class DiffusionRepositoryController extends DiffusionController { $header = id(new PHUIHeaderView()) ->setHeader($repository->getName()); - $icon = id(new PHUIIconView()) - ->setIcon('fa-folder-open'); - - $button = new PHUIButtonView(); - $button->setText(pht('Browse Repository')); - $button->setTag('a'); - $button->setIcon($icon); - $button->setHref($browse_uri); + $button = id(new PHUIButtonView()) + ->setText(pht('Browse')) + ->setTag('a') + ->setIcon('fa-code') + ->setHref($browse_uri); $header->addActionLink($button); $browse_panel->setHeader($header); diff --git a/src/applications/repository/storage/PhabricatorRepository.php b/src/applications/repository/storage/PhabricatorRepository.php index a0d4c6c7b5..f8a434e42b 100644 --- a/src/applications/repository/storage/PhabricatorRepository.php +++ b/src/applications/repository/storage/PhabricatorRepository.php @@ -699,6 +699,7 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO $action = idx($params, 'action'); switch ($action) { case 'history': + case 'graph': case 'browse': case 'change': case 'lastmodified': @@ -776,6 +777,7 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO switch ($action) { case 'change': case 'history': + case 'graph': case 'browse': case 'lastmodified': case 'tags': From cd19ddf111dc95a927488e9ae249b4911c88b08b Mon Sep 17 00:00:00 2001 From: epriestley Date: Mon, 19 Jun 2017 12:37:00 -0700 Subject: [PATCH 20/34] Improve validation errors for changing task priorities Summary: Ref T12124. Currently, Conduit provides a fairly rough error message if you provide an invalid priority. Instead, provide a more tailored message. Also, block `!!unknown!!` except from web edits. Test Plan: Before: {F5007964} After: {F5007965} Also, changed a priority to `999` in the database, edited it with the normal web UI form, it let me make the edit without being forced to adjust the priority. Reviewers: amckinley, chad Reviewed By: amckinley Maniphest Tasks: T12124 Differential Revision: https://secure.phabricator.com/D18135 --- .../ManiphestTaskPriorityTransaction.php | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/src/applications/maniphest/xaction/ManiphestTaskPriorityTransaction.php b/src/applications/maniphest/xaction/ManiphestTaskPriorityTransaction.php index 4e505668d1..2ed7c4e15b 100644 --- a/src/applications/maniphest/xaction/ManiphestTaskPriorityTransaction.php +++ b/src/applications/maniphest/xaction/ManiphestTaskPriorityTransaction.php @@ -129,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; + } + } From 474d528c3b85ec6639056be16d7fae7b536bf3bc Mon Sep 17 00:00:00 2001 From: epriestley Date: Mon, 19 Jun 2017 12:15:26 -0700 Subject: [PATCH 21/34] Allow numeric constants to act as aliases for task priorities in the web UI ` controls, so if the value comes in with something we don't recognize we'll treat it like some other value. Then alias all the numeric constants -- and other keywords -- to the right constants. This ended up only affecting the `" EditEngine fields canonicalize saved defaults Summary: Ref T12124. After D18134 we accept either "25" or "low" via HTTP parameters and when the field renders as a control, but if the form has a default value for the field but locks or hides it we don't actually run through that logic. Canonicalize both when rendering the control and when using a raw saved default value. Test Plan: - Created a form with "Priority: Low". - Hid the "Priority" field. - Before patch: Tried to create a task, was rebuffed with a (now verbose and helpful, after D18135) error. - Applied patch: things worked. Reviewers: chad, amckinley Reviewed By: amckinley Maniphest Tasks: T12124 Differential Revision: https://secure.phabricator.com/D18142 --- .../editfield/PhabricatorSelectEditField.php | 27 ++++++++++++------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/applications/transactions/editfield/PhabricatorSelectEditField.php b/src/applications/transactions/editfield/PhabricatorSelectEditField.php index b72cafc5d1..fa565dbe61 100644 --- a/src/applications/transactions/editfield/PhabricatorSelectEditField.php +++ b/src/applications/transactions/editfield/PhabricatorSelectEditField.php @@ -27,18 +27,13 @@ final class PhabricatorSelectEditField return $this->optionAliases; } + protected function getDefaultValueFromConfiguration($value) { + return $this->getCanonicalValue($value); + } + protected function getValueForControl() { $value = parent::getValueForControl(); - - $options = $this->getOptions(); - if (!isset($options[$value])) { - $aliases = $this->getOptionAliases(); - if (isset($aliases[$value])) { - $value = $aliases[$value]; - } - } - - return $value; + return $this->getCanonicalValue($value); } protected function newControl() { @@ -59,4 +54,16 @@ final class PhabricatorSelectEditField 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; + } + } From cdeba0f85b40e505d9b86fec8e5954507f0ba12e Mon Sep 17 00:00:00 2001 From: Chad Little Date: Wed, 21 Jun 2017 22:05:29 +0200 Subject: [PATCH 25/34] New icons for repositories Summary: Had some made, they seem better than my attempt. Test Plan: review in sandbox. Reviewers: epriestley Reviewed By: epriestley Subscribers: avivey, Korvin Maniphest Tasks: T12859 Differential Revision: https://secure.phabricator.com/D18143 --- resources/builtin/repo/building.png | Bin 2566 -> 4249 bytes resources/builtin/repo/cloud.png | Bin 1904 -> 7360 bytes resources/builtin/repo/code.png | Bin 2680 -> 3956 bytes resources/builtin/repo/commit.png | Bin 2103 -> 6622 bytes resources/builtin/repo/database.png | Bin 3428 -> 10938 bytes resources/builtin/repo/desktop.png | Bin 1193 -> 2484 bytes resources/builtin/repo/gears.png | Bin 4209 -> 9870 bytes resources/builtin/repo/globe.png | Bin 4171 -> 14281 bytes resources/builtin/repo/locked.png | Bin 2092 -> 6430 bytes resources/builtin/repo/microchip.png | Bin 1841 -> 5924 bytes resources/builtin/repo/mobile.png | Bin 1411 -> 3879 bytes resources/builtin/repo/repo.png | Bin 1590 -> 3406 bytes resources/builtin/repo/servers.png | Bin 1400 -> 6414 bytes 13 files changed, 0 insertions(+), 0 deletions(-) diff --git a/resources/builtin/repo/building.png b/resources/builtin/repo/building.png index 1638c4174dcca9d964625cbd884c1b48414438e0..d3ab581fe8584a1789948e9d965ebe286a354174 100644 GIT binary patch literal 4249 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 z za+@DL(9pK$-g`q(KgY1c-4^OSTKBW2xZ+gYl*b*te4pcezwX!l-;$l;rgmNS1#tq! zfmrJwOg@ff1Ki~ejRm$V3He)}zUwjBPy+kO&zEC@5be;A*cX53-JNyqW;{Ns!@E|} zdFx@X_o6b$|fE|7pwi$~gjRAV5d2<&Sl-IfjzM~vRVAM6pAw?z$ z_TsX7Ukfc3?dE**@hLzf&Q>T2Ju6HpRqku)^as&Z7}QT*Q!8iJfcgB;I-?kK^b>hl z=Y2|Rxau13H^;$k-fx&4DzW->%3kM$#;!h%R}NKW7K!QpW}@R6mX5hn=9ogpnT=y7 zx}6X`VZ3SSpj+O7V10oc6}ZxIa$y7{^q$_Q)2SWQ&pHP-R{mn1<-A;_jA~YGU8l??No)Ax;vi5gQdj7 zGJoTu9Wl+)Q7q$fU)NLNoFiv)e{*^52S0ra=?uB~ zZn$dFuwfwrl}K<>p zv=cwxlzV>m_^;TCfCYDt-J`+Bm2YqY`>^OQk%Vbz+V|0|okMGzw$NY>)57IT#Yal9 zMSy2 zj2Z?};*H-w@87rHS?jKK?>^`5z0Wz{-rp&)y3f@?WXxm)1Oy
gn{1cZV&4+#)2 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 delta 1864 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 JPDHLkV1gFXczFN- diff --git a/resources/builtin/repo/database.png b/resources/builtin/repo/database.png index 651a2d5bf7c6d9591f22f1053d94cfbb810a929b..4c9ec543fac2ee25c52e25a150eeff7e23c9d596 100644 GIT binary patch literal 10938 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 literal 3428 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 MHsr2%ofkaqU+lM0FaQ7m diff --git a/resources/builtin/repo/gears.png b/resources/builtin/repo/gears.png index 85d8392636b1748428647f20590d21b37ee98c10..11fd42c827d3f9fc0ceee521ae77edfc4440b62b 100644 GIT binary patch literal 9870 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 delta 4205 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�jEtDT_bwFn>H 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 X<-)99u0>e$zcJ*blqBoKK_UMGVeoS- literal 4171 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 diff --git a/resources/builtin/repo/locked.png b/resources/builtin/repo/locked.png index eeef06acd35261a6c96933d850fe9347b6ed3657..80e320c26a1f1581a679dc8a090dec3ccac7f225 100644 GIT binary patch literal 6430 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 CBUY>c literal 2092 zcmZ8h2~-l;8b+;V!m&-CQ%$M8sW;VRG-ac&vKhs1OgZ*V4;9ejA z0MN0qw!8)aXdK&E-)eoju}4K+1^_gD9j<^ct*x!CuBxPS^CI!o0B?ldKh)PR=;H`D z+@T@i_~g{AQn{p7uT4m1UUaa~7)r@=Qf^^QN+voyCO29G{j996 zyoyX{puXab$mZoEW0E#%Z)C!=N06Mrkc^1f{OH6&R8>t06078H~a z8k-sAmE?rf(o95EXAf7QSnOr<5YO;;gVV!f^2jZnlF8Y$?8-`f%dAueg*~rpq%Fvm zQHg~e40dx{cSs~6zqod4S_((v=w1Dxk%%Hx{o>*>j`%Vuy?k6Ula*inFe1B$H8?pf zO-w7Jv~@$`3iv}~Si%e8=tLF1b$DbvEGoC2OrKv+wA1>s^Rb*)!|n7wwOTzrD|-;0 zU0vIzQmLU?=mGvHiP9ODQt~tdRe^2p?c=ezL(D#2%Zr{8bVEF}B=%|X;?nZN@a*x4 z>C%eEM-e$oOUqr%S4nB*b22%-yFVxlmYV%MKBWX%N>r&-v`!Abu01)uoYBp#t)~ix z#Vj_zyLW&}?`v&mE-$a}1Y-nJ2O85fE1iEFoyQ*%t*)+$#-|{0$g)cEs7O*+UYC|r zaW6D8rvQtoX-!Nmt8b!B&CEr{Ba2ZDrO!z$4nO1xLb!)bVFWI zEs@mG(aDj^l{2%ld!eu=@yHBBRSpt&|8Z7RYgbglvpO<80a}`wi%}>S$HbGPW0L8a zxtQc4Vj~Tfi|HR2eo13x1ULlYx9sp$Ak zwkrUzImX7)0{mEGfm*MzNdo{NkON2FDcAUA&1Y;jO7+XIK33E-v;5`)5e7p1%mbhE zS6S8b6v2@9nbi9x#aDcJgTKwBdi#dqT_;CyB0sl&%j&^d?&MZe@^oMd! znB5f|5_4|Sqhsv#Ce^h|<}o%YHq|6s``BInGyU{i_5Qvx(on(Rt5YXV@+b2p5sbLzEH`1LitM172&V?{m>&E6mJU>#!Kddc{c=AIeZ^ z!T0)RoUA*T5h5zk{Z zB3XSX?Jc_ffHUzr`c!1eq4h96f_vQ;barHAVGW2MsM0rR4poP_g|;kL-43PeIc>(SK z+{mE1$|9IR9J+qqk#;zFDC~JtlA}2>$nBI43Z3jFx~qfUb(+x{wb%N+VM;jGq*-Eq z^oLN-l#07=ZvRq?whEK;b!pDN5F{|5Dc|%D6xO(r1l$?`%@3s*|IgF^`phN>$&g&w z&EeB;4xJ(7`ZIm5BBbs9m?MyF8!x%=$);pG3BRk{A*ybH%7+$*x>O4HNMoGAV(0~=OV0?pL@ z`jg^=d7lUu^4j!9&~4pRPw%f&;)TEX_ZtPC@*{{kPhG0lUq7Uc0|)LJ5k=6BVz@;= zd$=}QhzR!nM#i;9Glw3GC^_V_yKw@qTU4LDR!U)N_*tyq?n6%_A(GQ+Gf(410Xv+G zLEB`_mKUW7P15)+4w-I}a*T2?dXiydSczFdp5A5ZE^@zVPX3VdShfO`N8En^(ZF(< diff --git a/resources/builtin/repo/microchip.png b/resources/builtin/repo/microchip.png index 2e5aea3d0e76dfe48d602b28cd9eb115ada86a25..25da5810de071ac7f1eec17585d1be92e570a473 100644 GIT binary patch literal 5924 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 V(r7q5nC$xPP*zk|sFXJk`Y(oS%~}8e literal 1841 zcmZXUdo;C>l^(;FXk7PnEhOlWP#Ps6-yS?>UHI+ zdTo7URi&O0&*u~o;EAP(Wc1^N5@Z>vu#^<@q%^O%zNWsNL}jF8;k4QK?Og*stkF)!5WRb_mp$6uJIo#!Pe{WgrejjGs~*K5BVvovva8D~ zsnR9I=B9RYbF;Rgy^7FQ+t2||EEyi-3#P=Q?(1ac<<=qy45#pPrarm?6T=5>Xr$oqs zN@emH(fr)JOtz#L9_91+ua=fq3wZtc9~h zQmCuubKgSE39uS{v%`%iI_8VIbxvgAq4`B^R;rw;{yLY^Fh#T3y8h@Mn-=sGH2t3C_T2if*l5QPjm*llEqA}C{w9eUio0_j zBKTyy1!-pCZJ!obyyxpDQR{iy9EZfJ#7E6sGkjWa=~P&V?u?;7%640T8S+cUagUQpc9>i5um7DX?$~eP96382 z1|9Y;HTUwe)Ptpyyeh3RqEKVf()7q7f(0tEobIVocf{{J| zT5RtcngH&{J+k(utbbiWffJSTV3s!-6V%`hxpXEZ-%k_6Xm)yKu8(nTB{SI*c1O)&9 diff --git a/resources/builtin/repo/mobile.png b/resources/builtin/repo/mobile.png index b4ec5ee3f17bf73acc177ea2e7b344e99523e284..5c59ad9b078447669e9423ff8c32fcf596aff016 100644 GIT binary patch literal 3879 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 literal 1411 zcmchW{ZkSK7{@WJ3}0y4t5(`8+w$5joo#yAT(*3#ZD!`QEUkI@Rw|{W_!g)IN+MvO zi1-SkA|k$!7J?=wiIhnAZlIVU3OKJeXw_}qZGXVNchBATd4BlZJ@>tD-symomLOXY z006M`_VWB005EaX{B)Bc`LWKw4xb_rouAsC*H!Y ztgJlZi}0ll@i#HiiD*HeI2~Eq(>F9VGh2YCVequ+nOV``2s9N3O~Z-ABmCY${$p`h z_mih$*~FwG7FrN@qhMl6k(*zUS5Vo})yM4;E^3yV+xYCZo^(WsWOy_dn*VHgw2s+D zu3(cZ*>^Bii7@Qld(}LF=x$-vtt_H?QB%))R8!BbVQ`bv3G=ViX}3u&?Y;e?;l3x& z9`{R9vx!YD-HVG$Og1kjDZf`JiAh3JYg#GQoRJrkQrX1PvNj{9RHxHxwK{5TYk4)N zS2)Dt@S8aNv}|Glt`zNDdq z%DNhfq5uFunzyG%V6w?;UgrDI02vemZ7Xff2m6m^k%v&*)@5x2^!tIFoD$!Os~369kG zo9K84c`$B*vZl^wyOeY$-AM0-HOmJtK!f9@QO2ab{>%FW{=ZGjgaGHVFu)9{Ym?B+wo9MvX<(-cEe@(@eEul1 zleTT$?22mU`^+cX-)lcsRkSId9qZOBYdm`6j41VH=uzmd>3zS@6mHm-PCYiq9x$cmL+t&fct)9f1a8h(97zj% zbI0=VIc$~o+Z=!GSAO`=ax)KFIIFTBlN`m0{1QVaIu7kOuXOwdyTA5$c^u2s@^fc@ zyn`tMFSM4GhaWkY<+4eB!1vl3P-z5aGlYC-Q->hY>g{#wQ((}kT*x|uXD(y|B3@vF zfOiXYhV_+j;~w(YdK)wA!FVsjZgRMpt=6VMWVOM3bqu^SC2wAH%*+Vhhy}Z9#|~8U zR%HqU^iqd96OYV|PByhep{xmZM7qt{-}gzsdsE!DLyYV3i4k%mf{PyF_PNxpm3R2M zU8C8;4X&Z}Lsnym-d*BM7@&T<0+?h^v@4?k6K?I0ll&x^ZE#CN_$!c_dyp^$d3vF^ zVaS~x_TbvCv`QW0h!e)Wbxs0w>csBcMiRBGU;nXu-y0jz6#BmeT5?d3Yu!0TAByRH MBEYlZhw!Yw03mzW^#A|> diff --git a/resources/builtin/repo/repo.png b/resources/builtin/repo/repo.png index ca6c80ad7e52cb9c22f4a3065eff3c67ecd9a3e5..b3706f91bb800c41bf21d56402189ff834f95eb4 100644 GIT binary patch literal 3406 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 Z5J`)34G-@uUId3BXp_??9vizx{TGwBJTU+O literal 1590 zcmZuw3p5jY7$1tRQQceA>Gn9c$L$vCoaA(s>Zs(7Qh7D0Ohk7Y$}5CRNrqu;ig~m( zdtzHQd5j^i%`>wxLt-|u&Bm;5H{H3nZk^8k&iTK-@Av)w-|v6^U+Q@mM^ocX#sC1o z6!hCER{%iIa(S#W(0N>N@s7H~)cG^+4qB~tetw~=M@XU7$0j`vi_HnYn_Gx`*2aA) znVN2D>3)d71%+iq#iQxWro}}qmROaV`BXMNgTXTXNGY6^D=VM3AaV$kQ`4b$vYT6b z7_8>S#YL%XCN?SmW_X5RaFj0`;WT&Eak%6PHkMG8g(hX>67Js1zYj0D9gT!%;nT89 z6CM;MJuE_D%0%LESOg*|wfJ!{ZD{yaNL1FXXk=bd#h_>`I5LY>(~|v&ob#B1Cs!BY zD$5ug4E7n7-q6)6q_dit)vXH)3v+X7wR&EuR4puM5|T01>~=J!oItHDc)}>bGb<_^ z<#Oee^o>;ZMxmTzR=?m2#Myad9PxQxVFj_QuC}2A`H0fm(Z_D&<(JTN^Qonj8gAD> zM<;)5Trw$<)i?2iBQxXg7bHF`ii|_OnUTvC%Fb>9EF$yOxTKFSs;O^pZtJ}rgN(ah zpis=co{&B%Wetj6Wul0kJ%Ztp*ALRM5pgI+)r*$)zH}sE{PmP_PIWUJ(c3>%#%Q>c zkSCj-C6(93Cu4*|V>7b~UiUx^yS*6Ce2{^CR8-N<>+ctcRVuY$aO5Rlq|s;wgd;Bp zhO_d>ef^?LG-*zyE`C}m92!kde^OG)nvlp$esG5Y04so?Q}*t6^ky5Gi3WOWSJ2pj zgDKY5S|6Nq=;6etF)MU`lUWxP}F7!vg zVHR_1tiW#qB=pvV_(z^TsP)0Ab=4=IczqNrvc{3N}=&7pY5; z`azVHFoQJw`mc)3PHmC8;E?*1o3ZpQM?UNMB*l`pv<+;P?gnrgOVK!`pCO_U3>T^1n9^ln`@w!c%Hlphgn*3o5Jzzpr zw&r=$F?JeuvIP2mAKVgFElNafgV_@#B*U;P$#yo4moHkKgB=hSW)rxb5rGmCO4@mA zcQ?o&yxMi>H46<6z5ZjDmJm1y-6|o4nwS=O04uKmfhxi|&Eg#)ANtqvj(Z#*iSc*ybmBuC z2STEXhwS?>hgR=#xLDk~TPRIOMp?1=Eeo4G(f~IaPiFlJqxm Cm`s%b diff --git a/resources/builtin/repo/servers.png b/resources/builtin/repo/servers.png index 749c3c1a854ec23b69dfb319b8c70fdbf7b50570..3adb8a2fcdd46641672b1573a7e275a4b1c2e740 100644 GIT binary patch literal 6414 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 delta 1355 zcmV-R1+@B(GWZIR8Gi!+002&-en$WR0l832R7Lmq_m7pRh>oLcbB%O+lyP~IcYc<5 zf0uN8l#7z3wYkRR<>>M8^78WY>g(;p#?P9dv2AsazQWAY)!ToCoN#!N+uh>u@$!$B zsfCN7;^XJ!=IQI~?x3Z$Zg!B_+u($YpploVt+K$q!OP?1=YNiqr>U;IfQOx@t-H3m z#oyuOY;=unb&iIOqU`POnV+!k@9>+UvhMEiZ+DQGp08|lj^5wo_V)IIh@N?XnDg`W zue8Chv%%Kb-Og|x0snXTky1mHl?(gsK@pF5Vk(jE<%+%M}-g$tRiI1f8^!2B#yM2S2o};vUgPMJW zn{s-Rjg+U<*WJy}*Ri$2hmE53_4f7k^@EC^ijbwSwSU6s>FdD5&5V<#;Nj(_tGbq* zuCutqsII)Kuf5;k<(HkW&(YYEnylvM>aw=Oa(R;F=IQP2@8jj@g^Z!MyT;|`>c+{@ zoT9UJe3kX-ob3Pr1A0kBK~#7F?cIZRB?%YD(UVlvh}yPo+qP}n?hm6L&%E$By2!0j zrS9sz9|qwU|EtbQkwF%Jz~4blZS|>%K9W?U=p%JW^{Ep}EV0BAODwU(DyhDqv9U?4 zH2U=)FtE9~rL|40O4mDf zyMYsO7HeW;V^WgB84yM0idEXsc~NA( zSfw>Ch$0KcDy?Br>R4he9uq~Dh*jFsWl?DP3bD$V6otkoVwJISRTOCZIRD&PousfP zdRm+0E7tUNgV$$Z!^R|yP0`)v276X7wrq_qv$h%kdbfRE{9(sVOKByIy9V#xvuFI8 z31;O#K`gPv%8*!pVu>Y|SYE)*-rh;oXK(Zo0002kS6hAdMRrUy#y_#d5=$(x#1c!a z{Ra*n93oa4hYk;qh$Baj?G&qm<0qoSl#{uOwRGkFl^GaPpQKT{Ai6n~w^+3chA+rK zoK8|WbGG<^E>E$}MK+ElDV&d<1~xcHDW@h1T@b6B!%?VzWv5uBZ8;l7&WTmp&WkQt zQ^#6)NvzbdF8j<%A8SiX6uBZ+8CRpwm^!h_xDtgXf1JO;Z%}@V%@(OMcTwFt$lM8nJQKpJEG9%L&YlNMilzu z^5v8ad^I*n;lrNj?#P3@O*BJ449!4Ody>YsucOP&_x7w_)wf26@!uH#DyjMQyXNNR zG2j0mU{+4!enVs9j~-Zfx+7Nh#1cy^vBdIDX{Kswt4~dlK^GTf;%5swwqA~^j$!}+ N002ovPDHLkV1kWb_Z9#E From eb201fce3831d585b1879248eedcf225e295d1c6 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Thu, 22 Jun 2017 17:24:49 +0200 Subject: [PATCH 26/34] Fix AA in repository images Summary: Updated Files, no more AA issue. Test Plan: look Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Differential Revision: https://secure.phabricator.com/D18144 --- resources/builtin/repo/commit.png | Bin 6622 -> 10313 bytes resources/builtin/repo/gears.png | Bin 9870 -> 15975 bytes resources/builtin/repo/locked.png | Bin 6430 -> 8956 bytes 3 files changed, 0 insertions(+), 0 deletions(-) diff --git a/resources/builtin/repo/commit.png b/resources/builtin/repo/commit.png index 9ee209cf4b0548cb6276be21e75d2803e6c99528..e6d251f09538edda71b854ca34e8764e148bcc41 100644 GIT binary patch literal 10313 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 literal 6622 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Ν&aA~i5hbuH>_F$Fa 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 diff --git a/resources/builtin/repo/locked.png b/resources/builtin/repo/locked.png index 80e320c26a1f1581a679dc8a090dec3ccac7f225..34074731a097691b1f3178737637a44c756da279 100644 GIT binary patch literal 8956 zcmch7_cvTo*FU2rYNB@uqKyzl$!HNlltG9V(IcXl=w+CQ7D7Z25k&MpBI+ok8-ggK zwoMh?-fd*Cnzk@kA&m~iS|RaCxKsf=bhhkuZJxjc;dK2_(=R48)73#ZoXfpcyGk~ z*pxZ*gNT;*m+$r#A5!~8N_2KUzXfwBs)(gdl?c}Dlw0XT8^ubxQgn9A#gJlk0wWLs zNOf@}vuH9oDV*Hj`!=ijPT0@+EH;^lt7LPq!Xl^O;6J#M2fqhp<}Ww*PTlzoR2gFb zS5Kd1b%(_LZ+4KZc+%d8b9m=*_&HqE){J1ocgH_HsS2cFTTR4rdU1RzxeVb^$V3;G zRuEVj{iwwoJAENeq`hz)2^PdlwxECe{nLUgUqG!ip-gz1B|V``AIk>)IChFOk~>*L zyA;`!Fm`+A^HFA$rZ8p5)L*A3Q6&v!R^aftCuB{oLK7;K z0=1$=vOB9%m?mZDuSXY0jTc1(#5~iN$tHuPKMiz`wo3RB11i(fD|+Qg2BXAl+X}Aw zy#7Id!Mi`3;kI>d$0krwfZFmI+ni${QKh+XZwd)VqAn?k>Oz@k;s2;3gH&Dyfa(Q` z3$gvy_qta*YfzFezL$7LTg8&=!ZD78V~zD>ZKRo z`>73*gIrj71J9}$i5HkYbr6K9Ra#5EE#_+3P@wax%mPHT0Ib5QNt(}S!CCA8n{O_u zlJZ?~$vCK1`@kg76+q9#x5wa8O;_f|TrBQx*i^0W=m+l82)~N&&2V#(>xg9%f7Jv<4n^Q~VS)6|u4@2y{=~3Ra2Ls3cR(LKng$W23as zfq^d|SzLMkrpF^M(j2bZ+V1@xtn#o$R=w3B~^2VEXPd-BrokzgaVzoWtqyBYJYjF82$x zX+#nH_P`vkF13LoVJe=-x7d~Lsx9vE*anPv1U!3tG~hP4@KUIuE+YIBx=@A5)^QYM z<-6)%bY>{oMtcEP&8c6OqNIn8)_V$@%2Qx$enTX>!MdwXY+m5j7|facc$4bON161P z7A-HfPx|X0P~oI1)B7>EH)fG3@XnN}xFKZnf|!2e1K11r@|@AGV^$A=VTsT2dx;Su zRr?yVIS;UeT;xP%e6FUdE5or=Xei&o2z-eqKDPg9_B$CfFS&S_3ejXqOM3drSAuAM z5Oq2IlW<1-Jr@Dk=NfTfZg;%A7{zy=K1;udqByLPN4evDwOPL<9GliIktofjzeFM zPQrG+t>0nk=z9e=ksErJ+l*M)&}t)9Dj4V-`ik1RcFeV7^HnapiGzlce$g07&Ma_B zL$m5sDIcs(bVZFdUFTDwFr_LEu)>pZZnStz%c*-V8u;+9wyRrt={SBd3KNV5+?+7L zyJ1=`_c}5w)=qe33jJ_H%WAU+l366N0--zpcqzUw=5H{T1_VF z(waGE{#EfrwCYburRU>m5yN?riRftO)#y4$Oms2Fo`A}nf!p)i)nwn8~k=lFA;njYraco(3QEq^5P~9K;(Sk|0{o8fZo(w&~ax9cut5m?{`jJh( z*n|0LUG|ihDmv~uBT{o_f+z2@WcA6YTb}Z&F#sBEwZ(!5Us2Q}z7QOFZST4!)5jSy zZB0JKH}g3!ovknx{M}_>=Bf(0^XzO%Q=8YVB~oW62~1pWYjYJ#%>CtI0j$EFp&_ML znuSxKEx$Uxuih3xJdg$e5Y$S>eb@P)zlL1g@wbWZ=#Ls5g+#^2KQVdIG;guPbDr3t26Vlbcy6Os{OoPhT?Q5!xYO4yV7XzbBqiHW@xM zzol9eQL|QN7HByY8Ai*Uo$u*WeoM<;*2aFfJ418NIV|z1XW;xB&%BL9Nk(_oC};C- zH%(sUsSgM-NzdYsnOjy_gZQ8dl@>&(gY{~DQx+wiBS z$xQ{GzIIlv0D1AJK(ns?xDupGT`u=of8A|q8->)HVOVI(BodIIid-+hj0>(KwS)-{ z2-ri$%U7Nd;!oZ**RiHiXPqPOPJ}L@_2gIxbeyDHF&JxS+D@^?5b<9Kp8*rOR_r#0 zIj@`S2xVfMJQEQpPX|IqD5E?;7Xq86+;u}gA6q|j!n>a%7~B7@Z7sIN_XlT>HjjYc zV87MbTsqtUr@L>`mO%kD4}njT3~wuj6em^pVqI5Z{dHp7K@&DDZ@7M5gwyXU)yj0Q z!_6Wlq1KiqZ7^Te{X6^gOX#ypX!zqY)%HGh9OXpDLaya?3(a{Nx`Zu~@>%Opoi_&~SGE(1}V#ZI^MoVR4O?H{;tS>fsGp z*+A88V2O{P-2kT{jcjYpTZS?9#a3r-U=_K(jkr$uPHM%`q{y>|-?$Y?&?P56l%0^U zHM`?U+6MaawYvTu^^Z9w{7&?F3&mS+rr0k9ov5$w3Mra53P>wUv)V@Ps+3`X=VW& z&#;B7Gai*^?M_7xmG;7C7fxp6wCKZLNr%+X@yMINz zmi7h7VrH7GYzimjb?3RC-gh#uIKEEX(Z8ij?lWAVP`@KwK4iqTzS&(!^D;R&mbeVe zC}zBePVvRr^uE{?{R=;Dph$HyV?P*;dkyv_k})h^?)?E1YoecB4#Ux3MO=8G}>m^L0B| zfry4kxnFLE1hB{fyRUqtM1pycfngg`Ys|g+FdXoQu%;50n3n*Y1uab`sJ@StI_bJ@ z52YWh0k-Uzcl!bmix8VjQqerV(HO|(T>j%RT*b5WcV?2ZjHZq*=@H3v;D}%XU*1Vr zb81=b?l|7prry~$oMSiKIRR8gvDGr8tmOcl@pqMl&L@8Qm2L-({c&6p0Gw6^TJb}D zyscO34sFF&aCSw;Hnc+Kp45Y%?Or(fBRGaLr^9ykgzsf#aud%}L7w9QTzBD~RM_DS1S*)dsgO z8Lq2Ls;TJ0rtjf~gbP~xdqU%(^%cNxU?0~Ow`PayF9vCU_+ zc&RFXH2V5Z{-p{sDqh|rv)q?!03|Fv{qfS~#hdZAb>ZSLtb3zLOh;6-;`D;O@QR@D zJKj$h=7fg#B!K2)!KHhip+2|;vbku-u;oumsOmBf18xqb7p);(N;*&zJkI`PL z`rigRQ2&OIR#BSH2~~GqvhPL>#21Fe5yexW1cOEJTf`X-)>D(aE$1f*u6AGtd;DcO z`-)BNb7wYhKeMZ%M57;z&n^!7*BccmINkNP=D-)VnvN>NC?km$-HncOI_jQR=Ip0g zwQGc1_zr79jgcVm4Il;+^y(9 zGoUVCYMw1q3-v|)&FB?5_dPZ$y^;%hZ_R!x=zGisE9KZXPLD;TP6F4iS(Y6I5JX0tZL?*Q z9e4LohE?VH&c9S?mvs7G!m$Y6d~m#b;8^7!J&UWP#ck&WLyLlDBH9(G1FhKvH3@?m zX7ggp%t}QBvcA)&YPh303H{uMn4J&j^wH;j5i{QWP(xda6<}HY!x_PQRh_Sb&@X@d zyuI|Q)$|uZrFXaH@nY(4|JF#BBs-ii^m8z;@ONbj(>uI>U9NF$9<_LNiWathK^K1J zqH55^)W@$o<^tT{PQrH3m%bC=iz)12Zm6ufK5!uE2WzV4OP*P)dE#H2k#+8dnnj;a z9w{X6iXvWn_m#nAZGF*RR7FqPWw}h2ENs9VJlS~)4Fzwp*STqN*qb&q>6ZWGZD3H? zRVtGjsj9RRC|J^SmzFY5f!zbE$i8PYyz;QF2u0oFQAHUo?})XXviR!=O=@j9I|-UD z%lduN8u^=etfc=ugt}Y^<8X~fL*fGMuQ}sbW?b)eDf}#n6^GZ=4o)VuOfwMz`m-S zj^~K~TLp@=*oV;|-G}_@@LT-JxhTfuK118MN6$qN4+W)}&G{KQsKu|x(f)sAD@V}0 zEZFoNqRb{)pi;UrM?*^%Mq2rTUE#YG*+3nFics;r$%1_H*u|ey1n@~uZ4iUoY{&Ol zy3<*+A=B%V2XkiY5p*`-2BdvhP5rPPkKT79&{4*Eb$T2 ziqr??32X%}J2s~LO6u}WUkTFZ5#d*9|52yp;NdiS0M%!zn>^PQp9^I|*!*w8G$07zBqm*&MX3XW7_V1>us@$0pCV`u1hxnWA`dkZ zvT`R75b}~(liL5|lrmZRttaOP*?GXp!hnnrx?qg9bF^SpOx$(aS@JmRiAJpSD{Rv1 z7wCBVrC?}|#B*8_w&&68E^V1MAeHHvt=DX58NgBxsyhZ1>xXsGxSi#`n8iWVQ1S$u z5aYLtQOLRqj+@Jj4f;7fVjf6*8@nAT#7c1pq6DR#Z155<0_Y8zCqRL^)Xrr&YiJ5}7e`(ykt#p?M29K4s=ZF%}k7}Q~Cbz}Itm*Up7 z%}3F_;j5HaVtwkP-7U(vo^(n)5EM)fz3{wI>SWG88u@>8+L7AMfhW3asC4Jv6?6Z3 z`nj8S-eM-tdaoiA9&OB^f)8+QGauIIp@}uPuE#w%=#S^8qg-EfQo)ifL(5#RKGGB* z2I6R~80B8RvWuE*`wNn{ZsYbBWqhn((7&mAE_YNlBv#Iuk2>7!kk>aJ+O|#U8Ek`e zPQ1e)24V#%(hT%#`}+&F?b2^v{}BjN*gcn3cl_S;*p2>?Lu+>8(f@M zkZ%$VXT%N77r!+$X*Zg8h?;qqn(UaE(=h#U$*Ramtj6azr>j}Ic@|Qw03H%_02g!!5oVvSNjZo#?n=>=VGc-*69{R% z$f~hRzphO!t|}fMiG{^BO#3cbIUM)Xu?|_=uPwjE!qihk?Os8Csk3PH%_>_|9RAax z^L4&_y7DFYMzeVz|TKI9| z_?TV#wVx@p8wAm*gUQ2^No?T zij~tjwx@MF2w!(w?N_X=;c@Yckax!JSg-&fLE*TK_1^v@ukE2buFh|M^px4$hpWiQ z@y~YEcVD7QpzIT#7deXEGZ&08IiXh+d1)$GH^qTcUxAT`_X${%5?0k;Rd8e`TDgAj zWL$fhfJO`?(|=9O1Kn>lT>dMwxb+FqU{cX>%x}Bm1mP{ z@2bMmD++3(Rb6qy8?(y#_C6o+hN^DzPd?EAb+EN4*|$evg{Yn$@a)s4EB}}s_yV~H zMn64o(Sc)D{RW|&(^7A1dx5u04Kb;`z&Y2RjmGmy*aeq3t2F2rv zWdGU;^Pc$6DcjQLbE0&jb9v0>$}YrlagEN*o$6eeCSO|;{*kL@QEU?Joilt`7p<0$ zNTr8#xJ%uw+DA^tw#Q#xN`7L}hq-ENsXiopQHY&iE_&rJZEZOmVG&+dCYj@jekd?H z4M^QM%g}wI%QEb5s?^ixKvm7O+lX-%UQST*zc%pIDWvwvZ-BwQSO*dZD(h`X9FXlC zC~02_iK}gl2`X1bFCDaKx>sd=?v`z~kemljZ3okJ5B6hDgB{LXPoE!jEb}G6I&@WD zANF5+5Qm{eK7aH>6cPM$x$z!WGp&1xfV8yvDMyK2bpLyIbmRQdq@nHcwMjpVmL26f zlf&%C_R;cfmbc{I3*K7`i>?n2A~lO#JWiGwq@noC-zQGZ!l1y<4>Vg`bM|S?h$_0H~MeA?kH8G7SE9gJJ(w+EFG?L3#yAt z@|!T<`hSelms_+!e0dJBpaJ=!ErieJ(<#Th`9CsnZcJP|uIjh`=xs@zT4z0%>iS)j zrw_oO5t(|PFQ{lItaE-3(Z~w@4>{i`cEWp1o7o)th+fOJ^vq>Cq{~2Y!6N33wzAM- zS&CrHH@`XG4?_@$fM8mz)}D4Qy7*4kL=ieayO{2N({^7rLN`{NB8?%<(R)LAB(qfI z#Xe(=8)5ZN2@M!%XdSQ01y z>MbR1o?lKX%5fF|EQ33jTjDgH&vJjX7Nj@OX}B85-#5lAir$+t@OD3!Ai=y-iaQwE zoH3l=hk-tE-{rzrrI^ZGf zfKud5vXuqZozdms_2$VxO|`*FpF$-!>8ZR>FDH7NP3D~SV!3D+No3-s=1^+z!PTK>=>5!qW)qRqc z5aAiaWM66u)2eFmLS6;i@w?$CVyW*={9hHjG56)jDk47zFWvvUFpyj*f(ZV#T21Im zS*T(Ga>QdZiRHiqJO^`;`3pj7e1i#g(t8QX9bv>`nBlqWw zZp{;#3cA}xt-O<7$|1ap4}RY8EkFV?$H&R2Huz+?=%>-?=Hb7U)(R$QHJ(||*zQIh zDMSl2oFvh4*i7gIJhnX+8K}E=LB_zfNaoYeGSLI1+4~Ze<$b7FB-@)RnzM zcpH<3ia&eW<$Rc(W-KB z|#nGKjGd7kuWN%d3@Q`NLCqRvvfAW2Q$Yd=U zo`sGQ=KAEDY8(%Ch!5JViY5cj2dB0}ey+(hrCH1BKg5X)7%b35xHlW3EpDIpmh+WW ze-vY)+M>+nGAj6#;j;PG0MC?EM{A1Kw6|^PtpNsOagKHTn8E&5j*?cptK8a)-pBIz z&`bQC-W=FBaLyG|T^5P9z_f1pKgF7EpTFPnTTK3Cf4b(kfZx)6rpnV&vIRA-qob^k z+Yyo+PEhe2$+9!4^g7G%^d|h(h%$+6!oGZ&qC1?E`vYUqd6lZbexLl8$06;&>XDG& z!;uTH%xZc|%uuqTC?eFSl)fyTYg?U}#UwI-szPWOp{L?$q{V!D=w)ee8?f(1wA@OA znJ_*SlLxJ&bBVeSCcT>uKa?y>VLms@QkXJ*5SW)=3!Gl+ecrwMC&sV3e8vYp4C&A`2P1=VJ??of|EtLbsKfT}x9MBffA>L6Jii&; zRp_KHCM!bw=xxP)E}>$OY6>s|LMx-mlTH^6E%n(tj?bJA3hYYv3G44%r2z}Uc34lWRrD)~y2qOC@@!tGw zk?(Gq^9(#MaOyFZb@WgZNvkS1ud6SF$snE5=84+Mql!RelIicu>HhrQe4w@nQ53N% zrzt;A))eFT{fkHQro?}G)|%TnpoX2z?Bcz}yqiEe*Z2<2@s8&gG$3VdgI0Gz4}Pm& zin^QxDI56M7M=M|$Zp_4WAd8sHqEc)B#^F0$;bYNL>#yEU@LyE&*xchfsxTm?RNk{ zYU{!KSlP?vBWRkV?~0Wb*QyXj+T7^Sx!F5$16=igTJ~~A>Ik^w3FyZVB3~2G^{Kg@ z?TI8#Gi|a0%cQdc*btAl4N_~-n(8}j^1h~epan4fc(vcEnO3CxpivuWvCsQ5;Ca)~ zhrVN09!9q4+m2%%bZXK;IfnC``IW9z`>x$jj;kLwgJU#WOFm$KX6_03X{2s9e5BFH zqeqT*!!e~LTjxE|Qvu5&NP4U@`ml3+=wOb^!dl*%(NxD#LisW*ZOEp(B#@5zw!ELa zZSB9*>1Y_1q|@3p9!b?HA#5mw-Hq~QD4SgnE>8o0Azsvrl)JsL(plZ$O*2T(zJyIe zO>FjlCFTK|(HOHKa5<3wpRPgx&uwxlJ=4i0uWXMWK8V2DWrz>^AzkWL3o=gsbMBZj z^`Gu#lrH2~rDVmb-Nz~~+GqH?Z)De$dr&X>k13Z6`Hnp~7D~7Bz}W2;Ors`uO?igp z*6cHgs7dZb0BuhTj{loFR6l>sg99#KHEs2>yBZU99UW`vFmolD+06Rf^SuS0IscNF z(ObC;Y3|zDjwT*edB03cR8+I8GgwRBsUM71(IC%QF)I)m#RFtYZB&A%Citu4X}N5 zwA54fdS62IbTZw*7^6G+mO|;n%U{jhL(S5G7**Fc$IG}5usHo51cJhjl^ z+loqomyeYx8kaF&z0{52x>#u?qH?%amQX4DxYR5Xld;VsCDHf@*_b%6_0un<@W0t_ z@I;xKUs>1TW*>p{y7SE8CiqFcju14*-CGnM4`keN+Ih#*6lwZa6B%iL$tS%nAbuG@ z$5;|OArTVC;!g^L7QM2efc?sMce{b!_^nMTq!mXeSbhB0u<4DlU-2K^RkjK9OpC9d zN`b&zdmjJ4!8@swRB`R zd6Q8sr|J^MFZ>;Df-{KdM#Nu>d#?eM8y>y&wFNGH2T;8cK0wXn;e8IgIpJSHgI+uW z80@%|BJ$&5oiU|~#bwJw)8{#iL=&Knat>D|x!c>+x64|RWuXBn|4K82@F>M5^hP*! zRBGf$Dv>Eo(AiN~`9>eV0NAPEHY5vdKBD|~L9F;%Kx{XH=Bg1;>45^o>q}a29EgGR z9R9pmBaXa^{8{0N$I>MQQ31GZqp26X{=a&h>n|CW^D+aOdt{b?zgkGNHS`}=KCpfL EKf=AI#{d8T literal 6430 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 CBUY>c From 519bec3e6f365a72cbfa60c8d63ffffda56f6884 Mon Sep 17 00:00:00 2001 From: epriestley Date: Thu, 22 Jun 2017 10:23:47 -0700 Subject: [PATCH 27/34] Make searching by tags work in Phriction Summary: Fixes T12860. Some joins were being dropped because we didn't call `parent::...` Test Plan: - Tagged a document. - Searched for documents with that tag. - Before change: got all documents. - After change: got only tagged documents. Reviewers: chad Reviewed By: chad Maniphest Tasks: T12860 Differential Revision: https://secure.phabricator.com/D18145 --- src/applications/phriction/query/PhrictionDocumentQuery.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/applications/phriction/query/PhrictionDocumentQuery.php b/src/applications/phriction/query/PhrictionDocumentQuery.php index 24e7fbbef5..2736d825b5 100644 --- a/src/applications/phriction/query/PhrictionDocumentQuery.php +++ b/src/applications/phriction/query/PhrictionDocumentQuery.php @@ -163,7 +163,7 @@ final class PhrictionDocumentQuery } protected function buildJoinClauseParts(AphrontDatabaseConnection $conn) { - $joins = array(); + $joins = parent::buildJoinClauseParts($conn); if ($this->getOrderVector()->containsKey('updated')) { $content_dao = new PhrictionContent(); From bd3f441098a02f4e96947574af6c458d45b0d96d Mon Sep 17 00:00:00 2001 From: epriestley Date: Thu, 22 Jun 2017 10:41:10 -0700 Subject: [PATCH 28/34] Modularize "bin/cache" purgers Summary: Ref T12859. This is an older command with a lot of hard-coded flags. Modularize cache purging in a modern way so it can be extended. Test Plan: Ran `bin/cache purge --trace` with various valid and invalid flags. Reviewers: chad Reviewed By: chad Maniphest Tasks: T12859 Differential Revision: https://secure.phabricator.com/D18146 --- src/__phutil_library_map__.php | 10 ++ ...habricatorCacheManagementPurgeWorkflow.php | 142 ++++++------------ .../cache/purger/PhabricatorCachePurger.php | 30 ++++ .../PhabricatorChangesetCachePurger.php | 18 +++ .../purger/PhabricatorGeneralCachePurger.php | 18 +++ .../purger/PhabricatorRemarkupCachePurger.php | 18 +++ .../purger/PhabricatorUserCachePurger.php | 18 +++ 7 files changed, 161 insertions(+), 93 deletions(-) create mode 100644 src/applications/cache/purger/PhabricatorCachePurger.php create mode 100644 src/applications/cache/purger/PhabricatorChangesetCachePurger.php create mode 100644 src/applications/cache/purger/PhabricatorGeneralCachePurger.php create mode 100644 src/applications/cache/purger/PhabricatorRemarkupCachePurger.php create mode 100644 src/applications/cache/purger/PhabricatorUserCachePurger.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index f1fd9648cd..d7b197028f 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -2171,6 +2171,7 @@ phutil_register_library_map(array( 'PhabricatorCacheManagementPurgeWorkflow' => 'applications/cache/management/PhabricatorCacheManagementPurgeWorkflow.php', 'PhabricatorCacheManagementWorkflow' => 'applications/cache/management/PhabricatorCacheManagementWorkflow.php', 'PhabricatorCacheMarkupGarbageCollector' => 'applications/cache/garbagecollector/PhabricatorCacheMarkupGarbageCollector.php', + 'PhabricatorCachePurger' => 'applications/cache/purger/PhabricatorCachePurger.php', 'PhabricatorCacheSchemaSpec' => 'applications/cache/storage/PhabricatorCacheSchemaSpec.php', 'PhabricatorCacheSetupCheck' => 'applications/config/check/PhabricatorCacheSetupCheck.php', 'PhabricatorCacheSpec' => 'applications/cache/spec/PhabricatorCacheSpec.php', @@ -2320,6 +2321,7 @@ phutil_register_library_map(array( 'PhabricatorCelerityApplication' => 'applications/celerity/application/PhabricatorCelerityApplication.php', 'PhabricatorCelerityTestCase' => '__tests__/PhabricatorCelerityTestCase.php', 'PhabricatorChangeParserTestCase' => 'applications/repository/worker/__tests__/PhabricatorChangeParserTestCase.php', + 'PhabricatorChangesetCachePurger' => 'applications/cache/purger/PhabricatorChangesetCachePurger.php', 'PhabricatorChangesetResponse' => 'infrastructure/diff/PhabricatorChangesetResponse.php', 'PhabricatorChatLogApplication' => 'applications/chatlog/application/PhabricatorChatLogApplication.php', 'PhabricatorChatLogChannel' => 'applications/chatlog/storage/PhabricatorChatLogChannel.php', @@ -2930,6 +2932,7 @@ phutil_register_library_map(array( 'PhabricatorGarbageCollectorManagementCollectWorkflow' => 'infrastructure/daemon/garbagecollector/management/PhabricatorGarbageCollectorManagementCollectWorkflow.php', 'PhabricatorGarbageCollectorManagementSetPolicyWorkflow' => 'infrastructure/daemon/garbagecollector/management/PhabricatorGarbageCollectorManagementSetPolicyWorkflow.php', 'PhabricatorGarbageCollectorManagementWorkflow' => 'infrastructure/daemon/garbagecollector/management/PhabricatorGarbageCollectorManagementWorkflow.php', + 'PhabricatorGeneralCachePurger' => 'applications/cache/purger/PhabricatorGeneralCachePurger.php', 'PhabricatorGestureUIExample' => 'applications/uiexample/examples/PhabricatorGestureUIExample.php', 'PhabricatorGitGraphStream' => 'applications/repository/daemon/PhabricatorGitGraphStream.php', 'PhabricatorGitHubAuthProvider' => 'applications/auth/provider/PhabricatorGitHubAuthProvider.php', @@ -3748,6 +3751,7 @@ phutil_register_library_map(array( 'PhabricatorRegistrationProfile' => 'applications/people/storage/PhabricatorRegistrationProfile.php', 'PhabricatorReleephApplication' => 'applications/releeph/application/PhabricatorReleephApplication.php', 'PhabricatorReleephApplicationConfigOptions' => 'applications/releeph/config/PhabricatorReleephApplicationConfigOptions.php', + 'PhabricatorRemarkupCachePurger' => 'applications/cache/purger/PhabricatorRemarkupCachePurger.php', 'PhabricatorRemarkupControl' => 'view/form/control/PhabricatorRemarkupControl.php', 'PhabricatorRemarkupCowsayBlockInterpreter' => 'infrastructure/markup/interpreter/PhabricatorRemarkupCowsayBlockInterpreter.php', 'PhabricatorRemarkupCustomBlockRule' => 'infrastructure/markup/rule/PhabricatorRemarkupCustomBlockRule.php', @@ -4202,6 +4206,7 @@ phutil_register_library_map(array( 'PhabricatorUserBadgesCacheType' => 'applications/people/cache/PhabricatorUserBadgesCacheType.php', 'PhabricatorUserBlurbField' => 'applications/people/customfield/PhabricatorUserBlurbField.php', 'PhabricatorUserCache' => 'applications/people/storage/PhabricatorUserCache.php', + 'PhabricatorUserCachePurger' => 'applications/cache/purger/PhabricatorUserCachePurger.php', 'PhabricatorUserCacheType' => 'applications/people/cache/PhabricatorUserCacheType.php', 'PhabricatorUserCardView' => 'applications/people/view/PhabricatorUserCardView.php', 'PhabricatorUserConfigOptions' => 'applications/people/config/PhabricatorUserConfigOptions.php', @@ -7366,6 +7371,7 @@ phutil_register_library_map(array( 'PhabricatorCacheManagementPurgeWorkflow' => 'PhabricatorCacheManagementWorkflow', 'PhabricatorCacheManagementWorkflow' => 'PhabricatorManagementWorkflow', 'PhabricatorCacheMarkupGarbageCollector' => 'PhabricatorGarbageCollector', + 'PhabricatorCachePurger' => 'Phobject', 'PhabricatorCacheSchemaSpec' => 'PhabricatorConfigSchemaSpec', 'PhabricatorCacheSetupCheck' => 'PhabricatorSetupCheck', 'PhabricatorCacheSpec' => 'Phobject', @@ -7551,6 +7557,7 @@ phutil_register_library_map(array( 'PhabricatorCelerityApplication' => 'PhabricatorApplication', 'PhabricatorCelerityTestCase' => 'PhabricatorTestCase', 'PhabricatorChangeParserTestCase' => 'PhabricatorWorkingCopyTestCase', + 'PhabricatorChangesetCachePurger' => 'PhabricatorCachePurger', 'PhabricatorChangesetResponse' => 'AphrontProxyResponse', 'PhabricatorChatLogApplication' => 'PhabricatorApplication', 'PhabricatorChatLogChannel' => array( @@ -8253,6 +8260,7 @@ phutil_register_library_map(array( 'PhabricatorGarbageCollectorManagementCollectWorkflow' => 'PhabricatorGarbageCollectorManagementWorkflow', 'PhabricatorGarbageCollectorManagementSetPolicyWorkflow' => 'PhabricatorGarbageCollectorManagementWorkflow', 'PhabricatorGarbageCollectorManagementWorkflow' => 'PhabricatorManagementWorkflow', + 'PhabricatorGeneralCachePurger' => 'PhabricatorCachePurger', 'PhabricatorGestureUIExample' => 'PhabricatorUIExample', 'PhabricatorGitGraphStream' => 'PhabricatorRepositoryGraphStream', 'PhabricatorGitHubAuthProvider' => 'PhabricatorOAuth2AuthProvider', @@ -9204,6 +9212,7 @@ phutil_register_library_map(array( 'PhabricatorRegistrationProfile' => 'Phobject', 'PhabricatorReleephApplication' => 'PhabricatorApplication', 'PhabricatorReleephApplicationConfigOptions' => 'PhabricatorApplicationConfigOptions', + 'PhabricatorRemarkupCachePurger' => 'PhabricatorCachePurger', 'PhabricatorRemarkupControl' => 'AphrontFormTextAreaControl', 'PhabricatorRemarkupCowsayBlockInterpreter' => 'PhutilRemarkupBlockInterpreter', 'PhabricatorRemarkupCustomBlockRule' => 'PhutilRemarkupBlockRule', @@ -9756,6 +9765,7 @@ phutil_register_library_map(array( 'PhabricatorUserBadgesCacheType' => 'PhabricatorUserCacheType', 'PhabricatorUserBlurbField' => 'PhabricatorUserCustomField', 'PhabricatorUserCache' => 'PhabricatorUserDAO', + 'PhabricatorUserCachePurger' => 'PhabricatorCachePurger', 'PhabricatorUserCacheType' => 'Phobject', 'PhabricatorUserCardView' => 'AphrontTagView', 'PhabricatorUserConfigOptions' => 'PhabricatorApplicationConfigOptions', diff --git a/src/applications/cache/management/PhabricatorCacheManagementPurgeWorkflow.php b/src/applications/cache/management/PhabricatorCacheManagementPurgeWorkflow.php index 91ab0cf83d..d40c0f35e6 100644 --- a/src/applications/cache/management/PhabricatorCacheManagementPurgeWorkflow.php +++ b/src/applications/cache/management/PhabricatorCacheManagementPurgeWorkflow.php @@ -6,119 +6,75 @@ final class PhabricatorCacheManagementPurgeWorkflow protected function didConstruct() { $this ->setName('purge') - ->setSynopsis(pht('Drop data from caches. APC-based caches can be '. - 'purged from the web interface.')) + ->setSynopsis(pht('Drop data from readthrough caches.')) ->setArguments( array( array( - 'name' => 'purge-all', - 'help' => pht('Purge all caches.'), + 'name' => 'all', + 'help' => pht('Purge all caches.'), ), array( - 'name' => 'purge-remarkup', - 'help' => pht('Purge the remarkup cache.'), - ), - 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.'), + 'name' => 'caches', + 'param' => 'keys', + 'help' => pht('Purge a specific set of caches.'), ), )); } public function execute(PhutilArgumentParser $args) { - $console = PhutilConsole::getConsole(); + $all_purgers = PhabricatorCachePurger::getAllPurgers(); - $purge_all = $args->getArg('purge-all'); - - $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."'"; - } + $is_all = $args->getArg('all'); + $key_list = $args->getArg('caches'); + if ($is_all && strlen($key_list)) { throw new PhutilArgumentUsageException( pht( - "Specify which cache or caches to purge, or use '%s'. Available ". - "caches are: %s. Use '%s' for more information.", - '--purge-all', - implode(', ', $list), - '--help')); + 'Specify either "--all" or "--caches", not both.')); + } else if (!$is_all && !strlen($key_list)) { + throw new PhutilArgumentUsageException( + pht( + 'Select caches to purge with "--all" or "--caches". Available '. + 'caches are: %s.', + implode(', ', array_keys($all_purgers)))); } - if ($purge['remarkup']) { - $console->writeOut(pht('Purging remarkup cache...')); - $this->purgeRemarkupCache(); - $console->writeOut("%s\n", pht('Done.')); + if ($is_all) { + $purgers = $all_purgers; + } else { + $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 (!$purgers) { + throw new PhutilArgumentUsageException( + pht( + 'When using "--caches", you must select at least one valid '. + 'cache to purge.')); + } } - if ($purge['changeset']) { - $console->writeOut(pht('Purging changeset cache...')); - $this->purgeChangesetCache(); - $console->writeOut("%s\n", pht('Done.')); + foreach ($purgers as $key => $purger) { + echo tsprintf( + "%s\n", + pht( + 'Purging "%s" cache...', + $key)); + + $purger->purgeCache(); } - if ($purge['general']) { - $console->writeOut(pht('Purging general cache...')); - $this->purgeGeneralCache(); - $console->writeOut("%s\n", pht('Done.')); - } - - if ($purge['user']) { - $console->writeOut(pht('Purging user cache...')); - $this->purgeUserCache(); - $console->writeOut("%s\n", pht('Done.')); - } - } - - private function purgeRemarkupCache() { - $conn_w = id(new PhabricatorMarkupCache())->establishConnection('w'); - - queryfx( - $conn_w, - 'TRUNCATE TABLE %T', - id(new PhabricatorMarkupCache())->getTableName()); - } - - private function purgeChangesetCache() { - $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()); + return 0; } } diff --git a/src/applications/cache/purger/PhabricatorCachePurger.php b/src/applications/cache/purger/PhabricatorCachePurger.php new file mode 100644 index 0000000000..0115b45d7e --- /dev/null +++ b/src/applications/cache/purger/PhabricatorCachePurger.php @@ -0,0 +1,30 @@ +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(); + } + +} diff --git a/src/applications/cache/purger/PhabricatorChangesetCachePurger.php b/src/applications/cache/purger/PhabricatorChangesetCachePurger.php new file mode 100644 index 0000000000..fd6ff9940a --- /dev/null +++ b/src/applications/cache/purger/PhabricatorChangesetCachePurger.php @@ -0,0 +1,18 @@ +establishConnection('w'); + + queryfx( + $conn, + 'TRUNCATE TABLE %T', + DifferentialChangeset::TABLE_CACHE); + } + +} diff --git a/src/applications/cache/purger/PhabricatorGeneralCachePurger.php b/src/applications/cache/purger/PhabricatorGeneralCachePurger.php new file mode 100644 index 0000000000..f2dea1e1e5 --- /dev/null +++ b/src/applications/cache/purger/PhabricatorGeneralCachePurger.php @@ -0,0 +1,18 @@ +establishConnection('w'); + + queryfx( + $conn, + 'TRUNCATE TABLE %T', + 'cache_general'); + } + +} diff --git a/src/applications/cache/purger/PhabricatorRemarkupCachePurger.php b/src/applications/cache/purger/PhabricatorRemarkupCachePurger.php new file mode 100644 index 0000000000..2c416fff36 --- /dev/null +++ b/src/applications/cache/purger/PhabricatorRemarkupCachePurger.php @@ -0,0 +1,18 @@ +establishConnection('w'); + + queryfx( + $conn, + 'TRUNCATE TABLE %T', + $table->getTableName()); + } + +} diff --git a/src/applications/cache/purger/PhabricatorUserCachePurger.php b/src/applications/cache/purger/PhabricatorUserCachePurger.php new file mode 100644 index 0000000000..64f631c96b --- /dev/null +++ b/src/applications/cache/purger/PhabricatorUserCachePurger.php @@ -0,0 +1,18 @@ +establishConnection('w'); + + queryfx( + $conn, + 'TRUNCATE TABLE %T', + $table->getTableName()); + } + +} From 224c4692ee0e1d11950c18b55d43d82feeed1905 Mon Sep 17 00:00:00 2001 From: epriestley Date: Thu, 22 Jun 2017 10:52:40 -0700 Subject: [PATCH 29/34] Add a cache purger for builtin files Summary: Fixes T12859. Test Plan: - Loaded Diffusion builtin icons before recent updates, saw cached builtins. - Ran `bin/cache purge --caches builtin-file`. - Reloaded, saw new files. Reviewers: chad Reviewed By: chad Maniphest Tasks: T12859 Differential Revision: https://secure.phabricator.com/D18147 --- src/__phutil_library_map__.php | 2 ++ ...habricatorCacheManagementPurgeWorkflow.php | 4 ++++ .../PhabricatorBuiltinFileCachePurger.php | 22 +++++++++++++++++++ .../files/query/PhabricatorFileQuery.php | 18 +++++++++++++++ 4 files changed, 46 insertions(+) create mode 100644 src/applications/cache/purger/PhabricatorBuiltinFileCachePurger.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index d7b197028f..0384c4b5f8 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -2162,6 +2162,7 @@ phutil_register_library_map(array( 'PhabricatorBoolEditField' => 'applications/transactions/editfield/PhabricatorBoolEditField.php', 'PhabricatorBritishEnglishTranslation' => 'infrastructure/internationalization/translation/PhabricatorBritishEnglishTranslation.php', 'PhabricatorBuiltinDraftEngine' => 'applications/transactions/draft/PhabricatorBuiltinDraftEngine.php', + 'PhabricatorBuiltinFileCachePurger' => 'applications/cache/purger/PhabricatorBuiltinFileCachePurger.php', 'PhabricatorBuiltinPatchList' => 'infrastructure/storage/patch/PhabricatorBuiltinPatchList.php', 'PhabricatorBulkContentSource' => 'infrastructure/daemon/contentsource/PhabricatorBulkContentSource.php', 'PhabricatorCacheDAO' => 'applications/cache/storage/PhabricatorCacheDAO.php', @@ -7362,6 +7363,7 @@ phutil_register_library_map(array( 'PhabricatorBoolEditField' => 'PhabricatorEditField', 'PhabricatorBritishEnglishTranslation' => 'PhutilTranslation', 'PhabricatorBuiltinDraftEngine' => 'PhabricatorDraftEngine', + 'PhabricatorBuiltinFileCachePurger' => 'PhabricatorCachePurger', 'PhabricatorBuiltinPatchList' => 'PhabricatorSQLPatchList', 'PhabricatorBulkContentSource' => 'PhabricatorContentSource', 'PhabricatorCacheDAO' => 'PhabricatorLiskDAO', diff --git a/src/applications/cache/management/PhabricatorCacheManagementPurgeWorkflow.php b/src/applications/cache/management/PhabricatorCacheManagementPurgeWorkflow.php index d40c0f35e6..cfe42c918b 100644 --- a/src/applications/cache/management/PhabricatorCacheManagementPurgeWorkflow.php +++ b/src/applications/cache/management/PhabricatorCacheManagementPurgeWorkflow.php @@ -64,7 +64,11 @@ final class PhabricatorCacheManagementPurgeWorkflow } } + $viewer = $this->getViewer(); + foreach ($purgers as $key => $purger) { + $purger->setViewer($viewer); + echo tsprintf( "%s\n", pht( diff --git a/src/applications/cache/purger/PhabricatorBuiltinFileCachePurger.php b/src/applications/cache/purger/PhabricatorBuiltinFileCachePurger.php new file mode 100644 index 0000000000..a4bc682c02 --- /dev/null +++ b/src/applications/cache/purger/PhabricatorBuiltinFileCachePurger.php @@ -0,0 +1,22 @@ +getViewer(); + + $files = id(new PhabricatorFileQuery()) + ->setViewer($viewer) + ->withIsBuiltin(true) + ->execute(); + + $engine = new PhabricatorDestructionEngine(); + foreach ($files as $file) { + $engine->destroyObject($file); + } + } + +} diff --git a/src/applications/files/query/PhabricatorFileQuery.php b/src/applications/files/query/PhabricatorFileQuery.php index a2de5ca6ab..071ee03991 100644 --- a/src/applications/files/query/PhabricatorFileQuery.php +++ b/src/applications/files/query/PhabricatorFileQuery.php @@ -18,6 +18,7 @@ final class PhabricatorFileQuery private $isDeleted; private $needTransforms; private $builtinKeys; + private $isBuiltin; public function withIDs(array $ids) { $this->ids = $ids; @@ -54,6 +55,11 @@ final class PhabricatorFileQuery return $this; } + public function withIsBuiltin($is_builtin) { + $this->isBuiltin = $is_builtin; + return $this; + } + /** * Select files which are transformations of some other file. For example, * you can use this query to find previously generated thumbnails of an image @@ -416,6 +422,18 @@ final class PhabricatorFileQuery $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; } From 58df1b7d3be21a12ccb93cea537ff8a92a6fd703 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Thu, 22 Jun 2017 21:10:48 +0200 Subject: [PATCH 30/34] Add a top level tab navigation option to PHUITwoColumnView Summary: Builds out a responsive tab bar system for PHUITwoColumnView pages Test Plan: Tested at mobile, tablet, and desktop breakpoints {F5012429} {F5012430} Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Differential Revision: https://secure.phabricator.com/D18148 --- resources/celerity/map.php | 10 +-- src/view/phui/PHUITwoColumnView.php | 18 +++++ webroot/rsrc/css/phui/phui-list.css | 71 +++++++++++++++++++ .../rsrc/css/phui/phui-two-column-view.css | 12 ++++ 4 files changed, 106 insertions(+), 5 deletions(-) diff --git a/resources/celerity/map.php b/resources/celerity/map.php index 3e80c99baa..0619fc34f8 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -9,7 +9,7 @@ return array( 'names' => array( 'conpherence.pkg.css' => 'ff161f2d', 'conpherence.pkg.js' => 'b5b51108', - 'core.pkg.css' => '6d40b714', + 'core.pkg.css' => '37dd219b', 'core.pkg.js' => '5d80e0db', 'darkconsole.pkg.js' => '1f9a31bc', 'differential.pkg.css' => '4ec4a37a', @@ -166,7 +166,7 @@ return array( 'rsrc/css/phui/phui-info-view.css' => '6e217679', 'rsrc/css/phui/phui-invisible-character-view.css' => '6993d9f0', 'rsrc/css/phui/phui-lightbox.css' => '0a035e40', - 'rsrc/css/phui/phui-list.css' => '12eb8ce6', + 'rsrc/css/phui/phui-list.css' => 'dcafb463', 'rsrc/css/phui/phui-object-box.css' => '9cff003c', 'rsrc/css/phui/phui-pager.css' => 'edcbc226', 'rsrc/css/phui/phui-pinboard-view.css' => '2495140e', @@ -177,7 +177,7 @@ return array( 'rsrc/css/phui/phui-status.css' => 'd5263e49', 'rsrc/css/phui/phui-tag-view.css' => '93b084cf', 'rsrc/css/phui/phui-timeline-view.css' => '313c7f22', - 'rsrc/css/phui/phui-two-column-view.css' => 'ce9fa0b7', + 'rsrc/css/phui/phui-two-column-view.css' => '5b8cd553', 'rsrc/css/phui/workboards/phui-workboard-color.css' => '783cdff5', 'rsrc/css/phui/workboards/phui-workboard.css' => '3bc85455', 'rsrc/css/phui/workboards/phui-workcard.css' => 'cca5fa92', @@ -854,7 +854,7 @@ return array( 'phui-inline-comment-view-css' => 'ffd1a542', 'phui-invisible-character-view-css' => '6993d9f0', 'phui-lightbox-css' => '0a035e40', - 'phui-list-view-css' => '12eb8ce6', + 'phui-list-view-css' => 'dcafb463', 'phui-object-box-css' => '9cff003c', 'phui-oi-big-ui-css' => '19f9369b', 'phui-oi-color-css' => 'cd2b9b77', @@ -872,7 +872,7 @@ return array( 'phui-tag-view-css' => '93b084cf', 'phui-theme-css' => '9f261c6b', 'phui-timeline-view-css' => '313c7f22', - 'phui-two-column-view-css' => 'ce9fa0b7', + 'phui-two-column-view-css' => '5b8cd553', 'phui-workboard-color-css' => '783cdff5', 'phui-workboard-view-css' => '3bc85455', 'phui-workcard-view-css' => 'cca5fa92', diff --git a/src/view/phui/PHUITwoColumnView.php b/src/view/phui/PHUITwoColumnView.php index 1c56886f7a..d0443280b6 100644 --- a/src/view/phui/PHUITwoColumnView.php +++ b/src/view/phui/PHUITwoColumnView.php @@ -10,6 +10,7 @@ final class PHUITwoColumnView extends AphrontTagView { private $header; private $subheader; private $footer; + private $tabs; private $propertySection = array(); private $curtain; @@ -42,6 +43,12 @@ final class PHUITwoColumnView extends AphrontTagView { return $this; } + public function setTabs(PHUIListView $tabs) { + $tabs->setType(PHUIListView::TABBAR_LIST); + $this->tabs = $tabs; + return $this; + } + public function setFooter($footer) { $this->footer = $footer; return $this; @@ -91,6 +98,10 @@ final class PHUITwoColumnView extends AphrontTagView { $classes[] = 'phui-two-column-fluid'; } + if ($this->tabs) { + $classes[] = 'with-tabs'; + } + if ($this->subheader) { $classes[] = 'with-subheader'; } @@ -124,6 +135,12 @@ final class PHUITwoColumnView extends AphrontTagView { 'phui-two-column-header', $this->header); } + $tabs = null; + if ($this->tabs) { + $tabs = phutil_tag_div( + 'phui-two-column-tabs', $this->tabs); + } + $subheader = null; if ($this->subheader) { $subheader = phutil_tag_div( @@ -137,6 +154,7 @@ final class PHUITwoColumnView extends AphrontTagView { ), array( $header, + $tabs, $subheader, $table, $footer, diff --git a/webroot/rsrc/css/phui/phui-list.css b/webroot/rsrc/css/phui/phui-list.css index e571e228d8..5df6f4a210 100644 --- a/webroot/rsrc/css/phui/phui-list.css +++ b/webroot/rsrc/css/phui/phui-list.css @@ -144,6 +144,77 @@ border: none; } +/* - Two Column View, Responsive Navigations ----------------------------------- + + Sets a two column page with a responsive, top navbar + +*/ + +.phui-list-view.phui-list-tabbar { + list-style: none; + overflow: hidden; +} + +.phui-list-view.phui-list-tabbar > li { + list-style: none; + float: left; + display: block; +} + +.phui-list-view.phui-list-tabbar > li > * { + display: block; +} + +.phui-list-tabbar .phui-list-item-href { + color: {$bluetext}; + padding: 8px 24px; + line-height: 24px; + font-weight: bold; + font-size: {$biggerfontsize}; + border-top: 4px solid #fff; +} + +.phui-list-tabbar .phui-list-item-selected .phui-list-item-href { + color: {$sky}; + border-bottom: 4px solid {$sky}; +} + +.phui-list-tabbar .phui-list-item-selected .phui-list-item-href + .phui-icon-view { + color: {$sky}; +} + +.device-desktop .phui-list-tabbar .phui-list-item-href:hover { + color: {$sky}; + border-bottom: 4px solid $fff; + text-decoration: none; +} + +.phui-list-tabbar .phui-list-item-icon { + height: 20px; + width: 20px; + display: none; + font-size: 20px; + text-align: center; +} + +.device-phone .phui-list-tabbar .phui-list-item-icon { + display: inline-block; +} + +.device-phone .phui-list-tabbar .phui-list-item-name { + display: none; +} + +.device-phone .phui-list-tabbar .phui-list-item-href { + padding: 8px 16px; +} + +.device-phone .phui-list-view.phui-list-navbar > li { + float: none; + border: none; +} + /* - Status Colors ------------------------------------------------------------- Colors for navbars diff --git a/webroot/rsrc/css/phui/phui-two-column-view.css b/webroot/rsrc/css/phui/phui-two-column-view.css index d910cf71a0..7728980268 100644 --- a/webroot/rsrc/css/phui/phui-two-column-view.css +++ b/webroot/rsrc/css/phui/phui-two-column-view.css @@ -12,6 +12,7 @@ margin-bottom: 12px; } +.phui-two-column-view.with-tabs .phui-two-column-header, .phui-two-column-view.with-subheader .phui-two-column-header { margin-bottom: 0; } @@ -168,6 +169,17 @@ margin: 0 8px; } +.phui-two-column-tabs { + padding: 0 32px; + margin-bottom: 32px; + background: #fff; + box-shadow: 0 1px 3px 0 rgba(0,0,0,0.2); +} + +.device-phone .phui-two-column-tabs { + padding: 0 12px; +} + /* Info View */ .phui-two-column-view .phui-info-view { From 219ae8b6c950df6cc4af91efbe9696b001ddfdbd Mon Sep 17 00:00:00 2001 From: epriestley Date: Fri, 23 Jun 2017 07:51:32 -0700 Subject: [PATCH 31/34] Remove old "Landing Strategy" code Summary: Fixes T12869. This is a very old, pre-Drydock chunk of code from D7486 and some followups. It does three things: - "Land to Hosted Git": Obsoleted by Drydock, has been commented out in HEAD for a very long time with no complaints. Disabled by D8719 in 2014. - "Land to Hosted Mercurial": Could be obsoleted by Drydock with a fairly small amount of work, but currently has no replacement. Unclear if this sees any real use. Not actually disabled at HEAD. - "Land to GitHub": Use GitHub OAuth credentials to land to GitHub. This is sort of theoretically useful and has no analog today. Disabled by D13022 in 2015. This stuff was largely disabled a long time ago and we haven't seen users hitting issues with it. This could all be moved to an extension today if anyone still relies on it. Test Plan: Grepped for removed classes, browsed Differential. Reviewers: chad Reviewed By: chad Maniphest Tasks: T12869 Differential Revision: https://secure.phabricator.com/D18150 --- src/__phutil_library_map__.php | 12 -- .../PhabricatorDifferentialApplication.php | 8 - .../DifferentialRevisionLandController.php | 157 --------------- .../DifferentialGitHubLandingStrategy.php | 186 ------------------ .../DifferentialHostedGitLandingStrategy.php | 127 ------------ ...erentialHostedMercurialLandingStrategy.php | 106 ---------- ...erentialLandingActionMenuEventListener.php | 81 -------- .../landing/DifferentialLandingStrategy.php | 87 -------- 8 files changed, 764 deletions(-) delete mode 100644 src/applications/differential/controller/DifferentialRevisionLandController.php delete mode 100644 src/applications/differential/landing/DifferentialGitHubLandingStrategy.php delete mode 100644 src/applications/differential/landing/DifferentialHostedGitLandingStrategy.php delete mode 100644 src/applications/differential/landing/DifferentialHostedMercurialLandingStrategy.php delete mode 100644 src/applications/differential/landing/DifferentialLandingActionMenuEventListener.php delete mode 100644 src/applications/differential/landing/DifferentialLandingStrategy.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 0384c4b5f8..9deeb338f6 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -453,13 +453,10 @@ phutil_register_library_map(array( 'DifferentialGetRevisionCommentsConduitAPIMethod' => 'applications/differential/conduit/DifferentialGetRevisionCommentsConduitAPIMethod.php', 'DifferentialGetRevisionConduitAPIMethod' => 'applications/differential/conduit/DifferentialGetRevisionConduitAPIMethod.php', 'DifferentialGetWorkingCopy' => 'applications/differential/DifferentialGetWorkingCopy.php', - 'DifferentialGitHubLandingStrategy' => 'applications/differential/landing/DifferentialGitHubLandingStrategy.php', 'DifferentialGitSVNIDCommitMessageField' => 'applications/differential/field/DifferentialGitSVNIDCommitMessageField.php', 'DifferentialHarbormasterField' => 'applications/differential/customfield/DifferentialHarbormasterField.php', 'DifferentialHiddenComment' => 'applications/differential/storage/DifferentialHiddenComment.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', 'DifferentialHunk' => 'applications/differential/storage/DifferentialHunk.php', 'DifferentialHunkParser' => 'applications/differential/parser/DifferentialHunkParser.php', @@ -472,8 +469,6 @@ phutil_register_library_map(array( 'DifferentialInlineCommentQuery' => 'applications/differential/query/DifferentialInlineCommentQuery.php', 'DifferentialJIRAIssuesCommitMessageField' => 'applications/differential/field/DifferentialJIRAIssuesCommitMessageField.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', 'DifferentialLineAdjustmentMap' => 'applications/differential/parser/DifferentialLineAdjustmentMap.php', 'DifferentialLintField' => 'applications/differential/customfield/DifferentialLintField.php', @@ -548,7 +543,6 @@ phutil_register_library_map(array( 'DifferentialRevisionHeraldFieldGroup' => 'applications/differential/herald/DifferentialRevisionHeraldFieldGroup.php', 'DifferentialRevisionIDCommitMessageField' => 'applications/differential/field/DifferentialRevisionIDCommitMessageField.php', 'DifferentialRevisionInlinesController' => 'applications/differential/controller/DifferentialRevisionInlinesController.php', - 'DifferentialRevisionLandController' => 'applications/differential/controller/DifferentialRevisionLandController.php', 'DifferentialRevisionListController' => 'applications/differential/controller/DifferentialRevisionListController.php', 'DifferentialRevisionListView' => 'applications/differential/view/DifferentialRevisionListView.php', 'DifferentialRevisionMailReceiver' => 'applications/differential/mail/DifferentialRevisionMailReceiver.php', @@ -5411,13 +5405,10 @@ phutil_register_library_map(array( 'DifferentialGetRevisionCommentsConduitAPIMethod' => 'DifferentialConduitAPIMethod', 'DifferentialGetRevisionConduitAPIMethod' => 'DifferentialConduitAPIMethod', 'DifferentialGetWorkingCopy' => 'Phobject', - 'DifferentialGitHubLandingStrategy' => 'DifferentialLandingStrategy', 'DifferentialGitSVNIDCommitMessageField' => 'DifferentialCommitMessageField', 'DifferentialHarbormasterField' => 'DifferentialCustomField', 'DifferentialHiddenComment' => 'DifferentialDAO', 'DifferentialHostField' => 'DifferentialCustomField', - 'DifferentialHostedGitLandingStrategy' => 'DifferentialLandingStrategy', - 'DifferentialHostedMercurialLandingStrategy' => 'DifferentialLandingStrategy', 'DifferentialHovercardEngineExtension' => 'PhabricatorHovercardEngineExtension', 'DifferentialHunk' => array( 'DifferentialDAO', @@ -5436,8 +5427,6 @@ phutil_register_library_map(array( 'DifferentialInlineCommentQuery' => 'PhabricatorOffsetPagedQuery', 'DifferentialJIRAIssuesCommitMessageField' => 'DifferentialCommitMessageCustomField', 'DifferentialJIRAIssuesField' => 'DifferentialStoredCustomField', - 'DifferentialLandingActionMenuEventListener' => 'PhabricatorEventListener', - 'DifferentialLandingStrategy' => 'Phobject', 'DifferentialLegacyHunk' => 'DifferentialHunk', 'DifferentialLineAdjustmentMap' => 'Phobject', 'DifferentialLintField' => 'DifferentialHarbormasterField', @@ -5529,7 +5518,6 @@ phutil_register_library_map(array( 'DifferentialRevisionHeraldFieldGroup' => 'HeraldFieldGroup', 'DifferentialRevisionIDCommitMessageField' => 'DifferentialCommitMessageField', 'DifferentialRevisionInlinesController' => 'DifferentialController', - 'DifferentialRevisionLandController' => 'DifferentialController', 'DifferentialRevisionListController' => 'DifferentialController', 'DifferentialRevisionListView' => 'AphrontView', 'DifferentialRevisionMailReceiver' => 'PhabricatorObjectMailReceiver', diff --git a/src/applications/differential/application/PhabricatorDifferentialApplication.php b/src/applications/differential/application/PhabricatorDifferentialApplication.php index 403e60c8a9..e259c2f112 100644 --- a/src/applications/differential/application/PhabricatorDifferentialApplication.php +++ b/src/applications/differential/application/PhabricatorDifferentialApplication.php @@ -41,12 +41,6 @@ final class PhabricatorDifferentialApplication extends PhabricatorApplication { return "\xE2\x9A\x99"; } - public function getEventListeners() { - return array( - new DifferentialLandingActionMenuEventListener(), - ); - } - public function getOverview() { return pht( 'Differential is a **code review application** which allows '. @@ -69,8 +63,6 @@ final class PhabricatorDifferentialApplication extends PhabricatorApplication { => 'DifferentialRevisionEditController', $this->getEditRoutePattern('attach/(?P[^/]+)/to/') => 'DifferentialRevisionEditController', - 'land/(?:(?P[1-9]\d*))/(?P[^/]+)/' - => 'DifferentialRevisionLandController', 'closedetails/(?P[^/]+)/' => 'DifferentialRevisionCloseDetailsController', 'update/(?P[1-9]\d*)/' diff --git a/src/applications/differential/controller/DifferentialRevisionLandController.php b/src/applications/differential/controller/DifferentialRevisionLandController.php deleted file mode 100644 index 0e222370df..0000000000 --- a/src/applications/differential/controller/DifferentialRevisionLandController.php +++ /dev/null @@ -1,157 +0,0 @@ -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:

%s
', - $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

%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; - } - -} diff --git a/src/applications/differential/landing/DifferentialGitHubLandingStrategy.php b/src/applications/differential/landing/DifferentialGitHubLandingStrategy.php deleted file mode 100644 index b4ff727cbe..0000000000 --- a/src/applications/differential/landing/DifferentialGitHubLandingStrategy.php +++ /dev/null @@ -1,186 +0,0 @@ -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')); - } - } -} diff --git a/src/applications/differential/landing/DifferentialHostedGitLandingStrategy.php b/src/applications/differential/landing/DifferentialHostedGitLandingStrategy.php deleted file mode 100644 index cc0cf97998..0000000000 --- a/src/applications/differential/landing/DifferentialHostedGitLandingStrategy.php +++ /dev/null @@ -1,127 +0,0 @@ -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')); - } -} diff --git a/src/applications/differential/landing/DifferentialHostedMercurialLandingStrategy.php b/src/applications/differential/landing/DifferentialHostedMercurialLandingStrategy.php deleted file mode 100644 index 38f7160958..0000000000 --- a/src/applications/differential/landing/DifferentialHostedMercurialLandingStrategy.php +++ /dev/null @@ -1,106 +0,0 @@ -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')); - } -} diff --git a/src/applications/differential/landing/DifferentialLandingActionMenuEventListener.php b/src/applications/differential/landing/DifferentialLandingActionMenuEventListener.php deleted file mode 100644 index 2cf3eaa4e5..0000000000 --- a/src/applications/differential/landing/DifferentialLandingActionMenuEventListener.php +++ /dev/null @@ -1,81 +0,0 @@ -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); - } - } - -} diff --git a/src/applications/differential/landing/DifferentialLandingStrategy.php b/src/applications/differential/landing/DifferentialLandingStrategy.php deleted file mode 100644 index 2cec11fefe..0000000000 --- a/src/applications/differential/landing/DifferentialLandingStrategy.php +++ /dev/null @@ -1,87 +0,0 @@ -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); - } - } - -} From 988a52cf1acdfdc43577c6a58d7f29b3c25548ec Mon Sep 17 00:00:00 2001 From: epriestley Date: Fri, 23 Jun 2017 07:34:29 -0700 Subject: [PATCH 32/34] Fix ambiguous URI parsing in Youtube Remarkup rule Summary: Fixes T12867. Also: - Simplify the code a little. - Stop mutating this on text/mobile -- there's no inherent value in the "youtu.be" link so I think this just changes the text the user wrote unnecessarily. Test Plan: {F5013804} Reviewers: chad Reviewed By: chad Maniphest Tasks: T12867 Differential Revision: https://secure.phabricator.com/D18149 --- .../rule/PhabricatorYoutubeRemarkupRule.php | 32 +++++++++++-------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/src/infrastructure/markup/rule/PhabricatorYoutubeRemarkupRule.php b/src/infrastructure/markup/rule/PhabricatorYoutubeRemarkupRule.php index bad8e0eacf..25422b970d 100644 --- a/src/infrastructure/markup/rule/PhabricatorYoutubeRemarkupRule.php +++ b/src/infrastructure/markup/rule/PhabricatorYoutubeRemarkupRule.php @@ -2,34 +2,37 @@ final class PhabricatorYoutubeRemarkupRule extends PhutilRemarkupRule { - private $uri; - public function getPriority() { return 350.0; } public function apply($text) { - $this->uri = new PhutilURI($text); - - if ($this->uri->getDomain() && - preg_match('/(^|\.)youtube\.com$/', $this->uri->getDomain()) && - idx($this->uri->getQueryParams(), 'v')) { - return $this->markupYoutubeLink(); + try { + $uri = new PhutilURI($text); + } catch (Exception $ex) { + return $text; } - return $text; - } + $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; + } - public function markupYoutubeLink() { - $v = idx($this->uri->getQueryParams(), 'v'); $text_mode = $this->getEngine()->isTextMode(); $mail_mode = $this->getEngine()->isHTMLMailMode(); 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( 'div', array( @@ -45,6 +48,7 @@ final class PhabricatorYoutubeRemarkupRule extends PhutilRemarkupRule { 'frameborder' => 0, ), '')); + return $this->getEngine()->storeText($iframe); } From f704f905d26055fb37564e154cac77056e047169 Mon Sep 17 00:00:00 2001 From: epriestley Date: Mon, 19 Jun 2017 15:02:22 -0700 Subject: [PATCH 33/34] Let PhabricatorSearchCheckboxesField survive saved query data with mismatched types Summary: Fixes T12851. This should fix the error I'm seeing, which is: * `Argument 1 passed to array_fuse() must be of the type array, boolean given` There may be a better way to patch this up than overriding the getValue() method, however. Test Plan: - Changed the default "Tags" filter to specify `true` instead of `array('self')`, then viewed that filter in the UI. - Before patch: fatal. - After patch: page loads. Note that `true` is not interpreted as `array('self')`, but the page isn't broken, which is a big improvement. Reviewers: #blessed_reviewers, 20after4, chad, amckinley Reviewed By: #blessed_reviewers, amckinley Subscribers: Korvin Maniphest Tasks: T12851 Differential Revision: https://secure.phabricator.com/D18132 --- .../search/field/PhabricatorSearchCheckboxesField.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/applications/search/field/PhabricatorSearchCheckboxesField.php b/src/applications/search/field/PhabricatorSearchCheckboxesField.php index 5a552362bf..e1a72f4576 100644 --- a/src/applications/search/field/PhabricatorSearchCheckboxesField.php +++ b/src/applications/search/field/PhabricatorSearchCheckboxesField.php @@ -18,6 +18,14 @@ final class PhabricatorSearchCheckboxesField return array(); } + protected function didReadValueFromSavedQuery($value) { + if (!is_array($value)) { + return array(); + } + + return $value; + } + protected function getValueFromRequest(AphrontRequest $request, $key) { return $this->getListFromRequest($request, $key); } From a19859053300f7087615f305f0ec8cb2038f7d4c Mon Sep 17 00:00:00 2001 From: epriestley Date: Fri, 23 Jun 2017 12:06:04 -0700 Subject: [PATCH 34/34] Degrade more gracefully when ProfileMenu dashboards fail to render Summary: Ref T12871. This replaces a dead end UI (user totally locked out) with one where the menu is still available, if the default menu item is one which generates a policy exception (e.g., because users can't see the dashboard). Really, we should do better than this and not select this item as the default item if the viewer can't see it, but there is currently no reliable way to test for "can the viewer see this item?" so this is a more involved change. I'm thinking we get this minor improvement into the release, then pursue a more detailed fix afterward. Test Plan: - Added a dashboard as the top item in the global menu. - Changed the dashboard to be visible to only user B. - Viewed Home as user A. - Before patch: entire page is a policy exception dialog. - After patch, things are better: {F5014179} Reviewers: chad, amckinley Reviewed By: amckinley Maniphest Tasks: T12871 Differential Revision: https://secure.phabricator.com/D18152 --- .../search/engine/PhabricatorProfileMenuEngine.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/applications/search/engine/PhabricatorProfileMenuEngine.php b/src/applications/search/engine/PhabricatorProfileMenuEngine.php index 4b24e67c6b..7b1e213d20 100644 --- a/src/applications/search/engine/PhabricatorProfileMenuEngine.php +++ b/src/applications/search/engine/PhabricatorProfileMenuEngine.php @@ -238,7 +238,14 @@ abstract class PhabricatorProfileMenuEngine extends Phobject { case 'view': $navigation->selectFilter($selected_item->getDefaultMenuItemKey()); - $content = $this->buildItemViewContent($selected_item); + try { + $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()); if (!$content) { return new Aphront404Response();